Dynamically move elements to the inside of the viewport

151
August 06, 2017, at 11:22 AM

Codepen: https://codepen.io/anon/pen/LjxNGj

Javascript:

$(document).ready(function() {
    var regions = '../js/json/eveRegions.json';
    var systems = '../js/json/eveSystems.json';
    var constellations = [];
    var displayedSystems = [];
    var arrayX = [];
    var arrayY = [];
    function getRegions() {
        $.getJSON(regions, function(data) {
            data.forEach(function(regionData) {
                $('#regionSelect').append("<option id="+regionData.region_id+">"+regionData.name+"</option>")
            });       
        });
    }
    $('#regionSelect').change(function() {
        var selectedRegion = $(this).val();
        constellations = [];
        displayedSystems = [];
        arrayX = [];
        arrayY = [];
        $('#container').empty();
        $.getJSON(regions, function(data) {
            data.forEach(function(regionData) {
                if (selectedRegion == regionData.name) {
                    console.log(regionData);
                    regionData.constellations.forEach(function(constellation) {
                        constellations.push(constellation);
                    });
                    console.log(constellations);
                    getSystems();
                }
            });
        });
    });
    function getSystems() {
        $.getJSON(systems, function(data) {
            var systemCount = data.length;
            var index = 0;
            data.forEach(function(systemData) {
                index++;
                if(constellations.indexOf(systemData.constellation_id) > -1) {
                    var x = systemData.position.x / 100000000000000;
                    var y = systemData.position.y / 100000000000000;
                    arrayX.push(x);
                    arrayY.push(y);
                    displayedSystems.push(systemData);
                }
                if (index === systemCount) {
                    generateSystems();
                }
            });       
        });
    }
    function generateSystems() {
        var lowestX = Math.min.apply(Math, arrayX);
        var lowestY = Math.min.apply(Math, arrayY);
        var offsetX = Math.abs(lowestX);
        var offsetY = Math.abs(lowestY);
        displayedSystems.forEach(function(data) {
            var x = data.position.x / 100000000000000;
            var y = data.position.y / 100000000000000;
            var coordX = x + offsetX;
            var coordY = y + offsetY;
            var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            svg.setAttribute('id', data.name);
            svg.setAttribute('title', data.name);
            svg.setAttribute('class', 'system');
            svg.setAttribute('constellation-id', data.constellation_id);
            svg.setAttribute('style', 'margin-top:'+coordY+'px;margin-left:'+coordX+'px');
            svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
            document.getElementById('container').appendChild(svg);
        });
    }
    getRegions();
    $('#container').panzoom();
});

HTML:

<body>
      <select id="regionSelect"></select>
      <div id="container"></div>
    </body>

CSS:

select {
  position: absolute;
}
#container {
  .system {
    width: 4px;
    height: 4px;
    background: grey;
    border-radius: 12px;
    position: absolute;
    &:hover {
      background: red;
    }
  }
  .label {
    position: absolute;
    font-size: 10px;
  }
}

This script is creating several SVG elements inside a div dynamically. Each of these elements have different pixel offsets using x and y coordinates, like locations on a map.

Every time a new option is selected via the dropdown, a new set of locations are loaded.

You can see here that I'm dividing the original coordinates by 10 trillion to make them more manageable pixel-wise:

var x = systemData.position.x / 100000000000000;
                    var y = systemData.position.y / 100000000000000;

This works great, but the problem is that even still in some selection, the offsets are so large that the generated SVG elements get pushed outside of the viewport. I've somewhat countered this by taking the most negative coordinates and adding those values to the offsets which (in most cases) aligns the elements start at the topLeft, as seen here:

var lowestX = Math.min.apply(Math, arrayX);
        var lowestY = Math.min.apply(Math, arrayY);
        var offsetX = Math.abs(lowestX);
        var offsetY = Math.abs(lowestY);
        displayedSystems.forEach(function(data) {
            var x = data.position.x / 100000000000000;
            var y = data.position.y / 100000000000000;
            var coordX = x + offsetX;
            var coordY = y + offsetY;

What I'm looking for, is a different way to plot these locations/elements so that they are always within the main viewport. In simpler terms, right now some elements have a margin-top of 1000px or more and I'm looking for a fancy way to counter that.

Answer 1

First off, I suggest you fetch your regions and system data only once .. it will make your users much happier.

But, to answer your query, if you multiply the smallest X and Y values by -1 (to effectively make them the 0,0 origin point) then you will ensure every system displayed for a region starts with the smallest position.x at 0px and the smallest position.y at 0px.

Hope this helps!

$(document).ready(function() {
    var regions = '../js/json/eveRegions.json';
    var systems = '../js/json/eveSystems.json';
    var regionData = [];
    var systemData = [];
    var constellations = [];
    var displayedSystems = [];
    var arrayX = [];
    var arrayY = [];
    $('#regionSelect').change(function() {
        var selectedRegion = $(this).val();
        constellations = [];    
        displayedSystems = [];
        arrayX = [];
        arrayY = [];
        $('#container').empty();
        var filteredRegions = regionData.filter((r) => selectedRegion == r.name);
        filteredRegions.forEach((r) => {
            console.log(r);
            r.constellations.forEach((c) => constellations.push(c));
            console.log(constellations);
            getRegionSystems();
        });
    });
    function getRegionSystems() {
        // Clear out the previously displayed systems so we don't keep building the list
        displayedSystems = systemData.filter((s) => constellations.indexOf(s.constellation_id) > -1);
        displayedSystems.forEach((s) => {
            var x = s.position.x / 100000000000000;
            var y = s.position.y / 100000000000000;
            arrayX.push(x);
            arrayY.push(y);
        });
        generateSystems();
    }
    function generateSystems() {
        var lowestX = Math.min.apply(Math, arrayX);
        var lowestY = Math.min.apply(Math, arrayY);
        var offsetX = -1 * lowestX;
        var offsetY = -1 * lowestY;
        displayedSystems.forEach(function(data) {
            var x = data.position.x / 100000000000000;
            var y = data.position.y / 100000000000000;
            var coordX = x + offsetX;
            var coordY = y + offsetY;
            var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            svg.setAttribute('id', data.name);
            svg.setAttribute('title', data.name);
            svg.setAttribute('class', 'system');
            svg.setAttribute('constellation-id', data.constellation_id);
            svg.setAttribute('style', 'margin-top:'+coordY+'px;margin-left:'+coordX+'px');
            svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
            document.getElementById('container').appendChild(svg);
        });
    }
    function getRegions() {
        $.getJSON(regions, function(data) {
            data.forEach(function(regionData) {
                $('#regionSelect').append("<option id="+regionData.region_id+">"+regionData.name+"</option>")
            });    
            regionData = data;   
        });
    }
    function getSystems() {
        $.getJSON(systems, function(data) {
            systemData = data;
        });
    }
    getRegions();
    getSystems();
    // $('#container').panzoom();
});
READ ALSO
In a 2-column Bootstrap row, how do I get the right-column (which has a background image) to always be the same size as the left column?

In a 2-column Bootstrap row, how do I get the right-column (which has a background image) to always be the same size as the left column?

My Bootstrap page begins with a single row with two columnsIn the first column there is some text content that varies in size

188
Reorder divs based on one class that appears dynamically in one of the divs

Reorder divs based on one class that appears dynamically in one of the divs

I have some trouble putting an order for my divs in my flex containerWhat is challenging for me is to modify the order of my 7 recipes based on which one has the class "expanded"

130
Horizontal scrollbar appears in dev tools, but not in the website

Horizontal scrollbar appears in dev tools, but not in the website

I have run my website through the device bar on the dev tools and there is a horizontal scroll there (together with a locally hosted WP site)I tried browsing it in my device but there is no actual horizontal scroll - it only appears on dev tools

154
Magento 2 change background colour

Magento 2 change background colour

Okay so I have a basic understanding of css and HTML

207