Using Scale Transformation on SVG Element Group

I have included an SVG of a lamp that I designed using Sketch as a demonstration. My intention is for the lamp head to enlarge by a factor (e.g., 1.2 in this case) when the cursor hovers over it - indicating interactivity. However, the issue arises when hovering over the lamp head as its location also gets transformed. Firstly, I would like to understand what basis the scale uses for its transformation - is it the other transforms or the positional values in the ellipses/paths?

Secondly, how can I ensure that scaling takes place around the origin of the group () that I am focusing on?

I have attempted to substitute translates for x,y positions on the elements, as well as nesting svgs without success. I believe there is a core aspect of the svg framework here that I am not fully comprehending.

.interactive:hover {
  scale: 1.2;
}
<svg viewBox="0 0 1920 1080" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <svg>
        <g fill="none" fill-rule="evenodd" transform="translate(0 .832)">
            <path fill="#FCFC30" fill-opacity=".35"
                  d="M283.589311,155.632129 L373.36705,522.838236 C377.564302,540.005704 367.049864,557.325232 349.882396,561.522484 C347.399779,562.129455 344.853386,562.436827 342.297648,562.438029 L162.3966,562.522631 C144.72349,562.530942 130.389866,548.210793 130.381555,530.537683 C130.380345,527.962942 130.689882,525.397465 131.303454,522.896901 L221.426762,155.606192 C225.638338,138.442233 242.966634,127.942251 260.130594,132.153828 C271.714734,134.996266 280.756541,144.04562 283.589311,155.632129 Z"
                  transform="rotate(32 252.31 295.631)"></path>
            /* The following group needs to be made interactive */
            <g fill-rule="nonzero" transform="translate(264.313 121.836)" class="interactive" cursor="pointer">
                <ellipse fill="#EFCF6A" rx="17.298" ry="17.28" cx="41.1" cy="90.717"></ellipse>
                <path fill="#E5DBDA"
                      d="M0,68.8755609 C0,68.8755609 23.9403854,39.015945 48.4343057,32.3804748 L89.5342738,57.6782049 C89.5342738,57.6782049 95.6231579,89.4731662 76.9413543,118.641587 L0,68.8755609 Z"></path>
                <path fill="#E5DBDA"
                      d="M89.5342738,0.585513479 L97.5605301,5.2856382 C97.5605301,5.2856382 102.127193,8.32689537 100.88174,15.2388435 C97.8157022,29.5668288 94.0284052,43.7312658 89.5342738,57.6782049 L48.4343057,32.3804748 C48.4343057,32.3804748 73.6201447,6.52978886 79.0171102,2.52085895 C81.9461562,0.0899965767 85.9303942,-0.643174192 89.5342738,0.585513479 L89.5342738,0.585513479 Z"></path>
            </g>
            <polygon fill="#BFBEBA" fill-rule="nonzero"
                     points="351.731 188.715 524.683 188.65 524.678 200.692 351.726 200.757"
                     transform="rotate(22.9 438.204 194.704)"></polygon>
            <polygon fill="#BFBEBA" fill-rule="nonzero"
                     points="400.402 312.102 586.898 312.149 586.902 328.477 400.406 328.43"
                     transform="rotate(104.4 493.652 320.29)"></polygon>
            <ellipse cx="516.376" cy="230.602" fill="#E5DBDA" fill-rule="nonzero" rx="11.624"
                     ry="11.612"></ellipse>
            <path fill="#BFBEBA" fill-rule="nonzero"
                  d="M391.968793,463.396323 L508.764661,463.396323 C512.968159,463.396323 516.375767,466.800366 516.375767,470.999466 L516.375767,482.611539 L384.219304,482.611539 L384.219304,470.999466 C384.219304,468.958805 385.039816,467.003668 386.497246,465.573761 C387.954677,464.143853 389.926333,463.35922 391.968793,463.396323 Z"></path>
            <polygon fill="#BFBEBA" fill-rule="nonzero"
                     points="453.273 466.714 461.299 419.022 476.521 419.022 483.164 466.714"></polygon>
            <ellipse cx="469.879" cy="414.321" fill="#E5DBDA" fill-rule="nonzero" rx="16.606"
                     ry="16.589"></ellipse>
        </g>
    </svg>
</svg>

Answer №1

Let's start with a simple example. The red rectangle acts like a lamp, scaling from the top left corner (0,0). The correct solution is to move 0,0 to the center of the rectangle by using negative values for x and y. This concept applies to multiple shapes as well. In this case, the blue rectangle is nested within more groups, with scaling applied to the group without a transform already set. Instead of adjusting x and y values for all shapes individually, grouping and translating the group in the negative direction can achieve the desired result with 0,0 at the group's center.

If you take a look at the edits made to your drawing, two groups have been added. One group handles the scaling, while the other positions 0,0 at the center. The width and height values are calculated based on half of the entire group's dimensions. To determine these values, you can select the group/elements in an editor or use browser dev tools with the function getBBox(). Additionally, reverse values had to be added to the original group to ensure the lamp remains in its correct position.

I also rearranged the polygon drawing the arm to be above the lamp group so that it stays behind the lamp during scaling.

.hover:hover {
  scale: 1.2;
}
<svg viewBox="0 0 100 100" width="200">
  <rect class="hover" width="20" height="20" x="0" y="10" fill="red" />
  <g transform="translate(40 20)">
    <rect class="hover" width="20" height="20" x="-10" y="-10" fill="green" />
  </g>
  <g transform="translate(70 20)">
    <g class="hover">
      <g transform="translate(-10 -10)">
        <rect width="20" height="20" x="0" y="0" fill="blue" />
      </g>
    </g>
  </g>
</svg>

.interactive:hover > g {
  scale: 1.2;
}
<svg viewBox="0 0 1920 1080" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <svg>
        <g fill="none" fill-rule="evenodd" transform="translate(0 .832)">
            <path fill="#FCFC30" fill-opacity=".35"
                  d="M283.589311,155.632129 L373.36705,522.838236 C377.564302,540.005704 367.049864,557.325232 349.882396,561.522484 C347.399779,562.129455 344... /* Continuing content */
        </g>
    </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

Unique styling for underlines in pop-up with custom CSS

When exploring my codesandbox project, I encountered 2 questions: How can I create a custom underline CSS similar to the UI image below the file name and trash icon? I tried using text-decoration:none, but it doesn't match the UI. How do I center a U ...

How can I ensure that the Hamburger menu fully covers the entire viewport when it is open?

My hamburger menu is fully functional using CSS alone. However, when the menu opens, it doesn't fill the entire screen as I would like. Currently, my page content appears below the open menu, creating a cluttered look. https://i.sstatic.net/EtTsr.png ...

The columns in the table are hidden when resizing

There are three tables in my code. The first table does not have any margin set, while the next two tables have a margin-left property to slightly move them to the left side. However, when I resize the window, I'm unable to see the last column in the ...

Uncertainty surrounding the inherited styling of an element in HTML

I am seeking clarification on the distinction between two methods of writing HTML code: CSS file (applies to both the first and second way): .parent{ color:red; font-style: italic; } .child_1{ color:blue; } .child_2{ color:green; } First approach ...

Angular directive for D3 chart not displaying on the page

While working on a D3-based angular directive inspired by this code pen Here is my implementation. Check out the Codepen link angular.module('myApp', []). directive('barsChart', function ($parse) { var directiveD ...

What could be causing my Link to malfunction in my about.js file?

I've encountered an issue where clicking the link in my app doesn't produce any result, and I'm unsure of the cause. Below is the content of my app.js file: import './App.css'; import {BrowserRouter as Router, Routes, Route} from ...

Creating a stroke in SVG using JavaScript

I created a code that inserts a line into my svg page when I press a button Here is the html snippet: <body> <svg width="500" height="400"> </svg> <button id="btn1">Append text</button> </body> Below is the script us ...

During the initial cycle, the CSS keyframes animation may experience glitches, but it will run smoothly in subsequent cycles

Seeking advice on troubleshooting a CSS keyframes animation issue. I have created an animation with 5 frames where the background image fades and transitions to the next image smoothly in all cycles, except for the first cycle where it glitches before each ...

Adding emphasis to the text within a submit button using HTML and CSS

I am experimenting with styling an input submit button to resemble a regular hyperlink. Everything looks great using CSS, except for the fact that the underlining is not showing up. Here is my CSS: input.addemail { border: 0px; background-color: #1e ...

What is the trick to showing text underneath a font awesome icon?

My HTML code contains font awesome icons, and I'm looking to have text appear below each icon instead of next to it. Currently, the text is displayed midway to the right of each icon. <div class="icons"> <span class="fa-stack f ...

In order to implement the functionality in JavaScript, the .slider::-webkit-slider

I need to create a slider that adjusts the size of the dot based on the value input. For example, when the value is 1, the dot size should be 10px and for a value of 100, it should be 100px. Is there a way to dynamically change the height of .slider::-web ...

Progress Bar Modules

I am currently working on creating a customizable animated progress bar that can be utilized as follows: <bar [type]="'health'" [percentage]="'80'"></bar> It is functional up to the point where I need to adjust different p ...

How to customize GtkEntry in GTK3 with CSS to eliminate the default blue outline?

I've been working on customizing the theme of an application using Gtk3 and Css. I have successfully implemented my desired themes for the widgets by using gtk_widget_set_name and defining names in CSS. However, I am facing an issue with removing the ...

Implementing responsive images within Bootstrap 4 columns, utilizing both the srcset and sizes attributes

Lately, I've been facing an issue with image resizing on different devices. Despite using the "img-fluid" class to control image size based on container width, mobile devices with a CSS resolution of 360px were displaying larger images than expected. ...

Is there a way to encase numerous <tbody> elements together?

My table design has specific css requirements where I am using multiple <tbody> tags. It looks like this: Example with multiple tbody tags However, I also need a wrapper for the multiple tbody tags (similar to a common tbody parent) that can be scr ...

What causes the difference in CSS border-bottom-width rendering between IE and Chrome?

My ASP:MENU is styled with some CSS properties, such as setting the 'height' and 'line-height' of each element to 15px. This design appears fine in Internet Explorer but seems too cramped in Chrome. Additionally, a 'border-bottom-s ...

Scrolling animations do not support the Translate3d feature

I'm struggling to implement a smooth scroll effect on the header of my website. My approach involves using transform:translate3d for animation, with the goal of keeping the header fixed at the top and moving it out of view as the user scrolls down. I ...

The function fromEvent is throwing an error stating that the property does not exist on the type 'Event'

I'm attempting to adjust the position of an element based on the cursor's location. Here is the code I am currently using: this.ngZone.runOutsideAngular(() => { fromEvent(window, 'mousemove').pipe( filter(() => this.hove ...

Technique in CSS/SASS to repair a div

Seeking a solution for fixing divs with text in CSS. I am aware of the background-attachment: fixed; property which creates a fancy effect. Is there a similar property to "fix" divs with text or how can this be achieved in Typescript? Your insight would be ...

Tips on creating horizontally aligned buttons with full width

Currently, I am facing an issue while attempting to create three equal-sized buttons laid out horizontally. However, what I have accomplished so far is displaying three full-width buttons stacked vertically. Here's the code snippet: <section class= ...