Showing nested SVGs with custom formatting

I have a nested SVG (path) that I want to manipulate by centering and scaling the "inner" SVG relative to an "inner bounding box" - let's say a square of 500px^2. However, I am struggling with understanding how to adjust the viewport and scaling to achieve the desired effect.

Here is an example code snippet where I am attempting to achieve this, but haven't been able to comprehend the necessary viewport adjustments and scaling calculations:

<!DOCTYPE html>
<html>
<head>
    <style>
        #svg {
    background:silver;
}
path {
    stroke: red;
    stroke-width: 0.0001;
    fill: none;
}
    </style>
    <script src="/scripts/snippet-javascript-console.min.js?v=1"></script>
    </head>
<body>
    <script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
<svg id="svg" height="800" width="624" viewport="0 0 800 624" preserveAspectRatio="xMinYMin meet"></svg>
    <script type="text/javascript">
        function latLng2point(latLng) {

    return {
        x: (latLng.lng + 180) * (256 / 360),
        y: (256 / 2) - (256 * Math.log(Math.tan((Math.PI / 4) + ((latLng.lat * Math.PI / 180) / 2))) / (2 * Math.PI))
    };
}

function poly_gm2svg(gmPaths, fx) {

    var point,
    gmPath,
    svgPath,
    svgPaths = [],
        minX = 256,
        minY = 256,
        maxX = 0,
        maxY = 0;

    for (var pp = 0; pp < gmPaths.length; ++pp) {
        gmPath = gmPaths[pp], svgPath = [];
        for (var p = 0; p < gmPath.length; ++p) {
            point = latLng2point(fx(gmPath[p]));
            minX = Math.min(minX, point.x);
            minY = Math.min(minY, point.y);
            maxX = Math.max(maxX, point.x);
            maxY = Math.max(maxY, point.y);
            svgPath.push([point.x, point.y].join(','));
        }


        svgPaths.push(svgPath.join(' '))


    }
    return {
        path: 'M' + svgPaths.join(' M'),
        x: minX,
        y: minY,
        width: maxX - minX,
        height: maxY - minY
    };

}<pre><code><!DOCTYPE html>
<html>
<head>
    <style>
        #svg {
    background:silver;
}
path {
    stroke: red;
    stroke-width: 0.0001;
    fill: none;
}
    </style>
    <script src="/scripts/snippet-javascript-console.min.js?v=1"></script>
    </head>
<body>
    <script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
<svg id="svg" height="800" width="624" viewport="0 0 800 624" preserveAspectRatio="xMinYMin meet"></svg>
    <script type="text/javascript">

// Additional content omitted for brevity...

In this example, a Google encoded polyline is used which may change frequently. My goal is to constrain any given path within the boundaries of a 500px square while keeping it centered.

If you have any suggestions or pointers on how to achieve this effect, especially in dealing with SVG absolute positioning challenges, please share your insights.

This code uses basic SVG functionality, but I am open to using JavaScript libraries if they can simplify the process of handling positioning constraints effectively. Any recommendations?

EDIT: For reference, here is a conceptual image of the intended outcome: https://i.sstatic.net/bnXNK.png

Answer №1

To achieve a 624*800px SVG with a central area of 500*500px for drawing paths, you can insert a nested SVG of the desired size at the specific location you want it to appear. Since you are aware of the dimensions of the outer SVG, determining its position manually is quite straightforward. You should omit the viewBox attribute in the markup.

In your code for the outer SVG, there are some errors: the attribute name should be viewBox, and the correct order is width before height:

viewBox="0 0 624 800"

When adding the path to the inner <svg> element (no <g> needed), set its viewBox using the values obtained from the properties of the path. That's all.

function latLng2point(latLng) {
    return {
        x: (latLng.lng + 180) * (256 / 360),
        y: (256 / 2) - (256 * Math.log(Math.tan((Math.PI / 4) + ((latLng.lat * Math.PI / 180) / 2))) / (2 * Math.PI))
    };
}

function poly_gm2svg(gmPaths, fx) {
    var point,
    gmPath,
    svgPath,
    svgPaths = [],
        minX = 256,
        minY = 256,
        maxX = 0,
        maxY = 0;

    for (var pp = 0; pp < gmPaths.length; ++pp) {
        gmPath = gmPaths[pp], svgPath = [];
        for (var p = 0; p < gmPath.length; ++p) {
            point = latLng2point(fx(gmPath[p]));
            minX = Math.min(minX, point.x);
            minY = Math.min(minY, point.y);
            maxX = Math.max(maxX, point.x);
            maxY = Math.max(maxY, point.y);
            svgPath.push([point.x, point.y].join(','));
	      }

        svgPaths.push(svgPath.join(' '))
    }
    return {
        path: 'M' + svgPaths.join(' M'),
        x: minX,
        y: minY,
        width: maxX - minX,
        height: maxY - minY
    };
}

function drawPoly(svg, props) {
    path = document.createElementNS("http://www.w3.org/2000/svg", 'path');
    path.setAttribute('d', props.path);
    svg.setAttribute('viewBox', [props.x, props.y, props.width, props.height].join(' '));
    svg.appendChild(path);
}

function init() {
    for (var i = 0; i < paths.length; ++i) {
        paths[i] = google.maps.geometry.encoding.decodePath(paths[i]);
    }

    svgProps = poly_gm2svg(paths, function (latLng) {
        return {
            lat: latLng.lat(),
            lng: latLng.lng()
        }
    });
    drawPoly(document.querySelector('#svg svg'), svgProps)
}

//array with encoded paths, will be decoded later
var paths = ["ki{eFvqfiVqAWQIGEEKAYJgBVqDJ{BHa@jAkNJw@Pw@V{APs@^aABQAOEQGKoJ_FuJkFqAo@{A}@sH{DiAs@Q]?WVy@`@oBt@_CB]KYMMkB{AQEI@WT{BlE{@zAQPI@ICsCqA_BcAeCmAaFmCqIoEcLeG}KcG}A}@cDaBiDsByAkAuBqBi@y@_@o@o@kB}BgIoA_EUkAMcACa@BeBBq@LaAJe@b@uA`@_AdBcD`@iAPq@RgALqAB{@EqAyAoOCy@AmCBmANqBLqAZ...
init();
#svg {
    background:silver;
}
path {
    stroke: red;
    stroke-width: 0.0001;
    fill: none;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>

<svg id="svg" height="800" width="624" viewBox="0 0 624 800" preserveAspectRatio="xMinYMin meet">
    <svg x="62" y="150" width="500" height="500"></svg>
</svg>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

AngularJS: Exploring the Depths of Nested Object Loops

{ name: 'Product One', visibility: 1, weight: '0.5', price: '19.99' custom_attributes: [ { attribute_code: 'image', value: '.img' }, { ...

Ensure the table row remains on one page when printing or viewing the print preview

I'm currently dealing with an html report that contains a table, which can be seen here http://jsfiddle.net/fhwoo3rg/2/embedded/result/ The issue arises when trying to print the report, as it breaks in the middle of a table row like this: https://i ...

Generating random objects in a straight line with Javascript and HTML5: A step-by-step guide

In my current project, I am developing a game using Javascript/HTML5 (within a canvas element) that features two distinct types of objects (referred to as object type A and object type B) falling from the top of the canvas. The goal for players is to swip ...

Why isn't my Bootstrap-styled radio button triggering auto post back?

I am facing an issue with the interaction between bootstrap and asp.net radio buttons. Specifically, the 'AutoPostBack' command is not functioning as expected. Here is the code snippet: Linked Bootsrap & JS Files: <link href="css/mycss.css" ...

Ensuring Proper Tabulator Width Adjustment Across All Browser Zoom Levels

<div id="wormGearTabulatorTable" style="max-height: 100%; max-width: 100%; position: relative;" class="tabulator" role="grid" tabulator-layout="fitDataTable"><div class="tabulator-header" role="rowgroup"><div class="tabulator-header-co ...

The console is displaying an undefined error for _co.photo, but the code is functioning properly without any issues

I am facing an issue with an Angular component. When I create my component with a selector, it functions as expected: it executes the httpget and renders a photo with a title. However, I am receiving two errors in the console: ERROR TypeError: "_co.photo ...

The Angular application will only display updated dynamic content upon refreshing the page

I am utilizing a factory to access my server-side data, using $routeParams to pass the id in the server request. Initially, everything functions correctly, but issues arise after the first run through the program. Here is a snippet of my code: Controller: ...

How can I adjust the size of the renderer in Three.js to fit the screen?

Encountering issues with the code snippet below: //WebGL renderer renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); //TODO: set optimal size document.body.appendChild(renderer ...

I'm working with an array of objects that I've pulled from an API, but the content is currently in String format. How can I properly convert it into a date?

Utilizing the moment library, my array is structured as follows: data: [ { "id": "610", "description": "New Test", "start": "2021-08-04T14:20:00.0 ...

Is there any way to determine if Bootstrap has been utilized to build my WordPress page?

I'm currently contemplating if it's worth incorporating Bootstrap into my pre-existing Wordpress site. During my research, an interesting thought crossed my mind - could the template I'm utilizing already be built with Bootstrap? Although a ...

Mapping DOM elements to VueJS components for hydration is a key process in facilitating

I have a specific requirement and I am exploring potential solutions using VueJS, as it offers the convenient feature of hydrating pre-rendered HTML from the server. In my Vue components, I do not define a template within the .vue file, but I need them to ...

Double f span causing unusual behavior in Chrome browser

Why does the highlight focus on "ort" instead of "fort"? It appears this occurs when there are two f's. When I substitute f with other letters, like d, it shows correctly. Could this be a bug in Chrome? Chrome version is chrome83. add: It seems to be ...

What is the response of Express when it encounters numerous identical asynchronous requests from the same origin?

Currently, I am utilizing Express.js for my project. There is an async function that performs a task that can take anywhere from 20 to 30 seconds to complete. Once the task is done, it increases a user's counter in the database. However, users are req ...

Troubleshooting issues with Three.js and .obj file shadows

I've been diving into learning Thee.js, and while it's fairly straightforward, I've hit a roadblock with getting shadows to work. Despite setting castShadows, recieveShadows, and shadowMapEnabled to true in the appropriate places, shadows ar ...

Ways to expand the height of content using grid?

I'm having trouble getting my grid template to stretch content to the end using CSS Grid. The behavior is unexpected, and I want to create a Jeopardy game where clicking on a box reveals a question. Initially, I applied display: grid to the body elem ...

Utilizing Firebase authentication to sign in via phone number in conjunction with Express on Node.js

Encountering an issue while implementing backend Firebase Authorization. After thoroughly reading the documentation (https://firebase.google.com/docs/auth/web/phone-auth), I came to understand that Authorization requires two steps: send phone send code ...

Implementing automatic vertical scrolling for dynamically added rows in a table's body

Check out this fiddle I created: https://jsfiddle.net/desytec/m69q2xwr/34/ <style> .table-scroll tbody { position: absolute; overflow-y: auto; height: 250px; } </style> <script> var count = 0; $(document).ready(function () ...

Guide to adding a checkbox to a JavaScript list

I'm currently working on building a task list using JavaScript. The concept is to type something into the input field and then, when the user clicks the button, a checkbox with that text will be generated. However, I'm facing an issue as I am no ...

Script for Detecting Table Header Presence in Office Fails to Identify Absence of Header

Currently, I am developing a macro in Office Scripts for Excel that has several requirements: Verify the existence of a column header in a specified table If the column does not exist, add it and set the desired header Write values to that newly added col ...

Submitting a form and obtaining results without relying on jQuery

Finding information on how to accomplish this task without using jQuery has proven to be a challenge. It seems like everyone is pushing for jQuery for even the simplest tasks nowadays. Despite avoiding unnecessary use of jQuery in creating a rich experienc ...