Tips for setting the background color of an SVG image as a percentage

Is it possible to dynamically fill a SVG image with color based on a percentage?

I would like to be able to change the color of an SVG image based on a specified percentage.

For example, I have an SVG image of the moon and I want to fill it with white color based on the illumination percentage of the moon.

So if the illumination percentage is 90%, the moon should be filled with 90% white color, and so on.

<?xml version="1.0" encoding="iso-8859-1"?> 
<svg xmlns="http://www.w3.org/2000/svg" width="139" height="134"> 
<g> 
  <circle stroke-width="7" stroke="#000" fill="#fff" r="58" cy="69" cx="69"/>
  <path stroke-width="0" fill="#000" d="m69,9 a62,60 0 0 0 1,121 l0,-5 a70,68 0 0 1 0,-110 l0,-5 z"/>
 </g></svg>

Answer №1

To create an elliptical shadow, I would use a mask.

// Adding event listener to input slider
var control = document.getElementById("control");
control.addEventListener("input", setMoonPhase);

// Initializing SVG based on initial slider value
setMoonPhase();

function setMoonPhase(evt) {
  // Converting percentage to a value between 0 and 1
  var val = control.value / 100;
  // Selecting the ellipse element representing moon phase
  var  phaseEllipse = document.getElementById("phase-ellipse");
  // Adjusting X radius of the phase ellipse (where 100% = 0.5 -> 50% = 0 -> 0% = 0.5)
  phaseEllipse.rx.baseVal.value = Math.abs(val - 0.5);
  // Setting fill color of ellipse based on phase
  phaseEllipse.style.fill = (val > 0.5) ? "white" : "black";
}
<svg xmlns="http://www.w3.org/2000/svg" width="139" height="134">
  <defs>
    <mask id="phase-mask" maskContentUnits="objectBoundingBox">
      <rect x="0.5" y="0" width="0.5" height="1" fill="white"/>
      <ellipse id="phase-ellipse" cx="0.5" cy="0.5" rx="0.2" ry="0.5" fill="white"/>
    </mask>
  </defs>
  <circle fill="black" r="58" cy="69" cx="69"/><!-- moon shadow -->
  <circle fill="#fff" r="54.5" cy="69" cx="69" mask="url(#phase-mask)"/><!-- sunlight on moon -->
  <circle stroke-width="7" stroke="black" fill="none" r="58" cy="69" cx="69"/><!-- moon border -->
</svg>

<p>
<input id="control" type="range" min="0" max="100" value="90" /><span id="output"></span>
</p>

Answer №2

If I were to tackle this, my approach would involve using the clip-path property.

mooning()

control.addEventListener("input",()=>{
mooning()
})

function map(n, a, b, _a, _b) {
  let d = b - a;
  let _d = _b - _a;
  let u = _d / d;
  return _a + n * u;
}

function mooning(){
output.innerHTML = control.value + "%";
let value = map(control.value, 0, 100, -25, 175)
moon.setAttributeNS(null, "cx", value)
}
svg{border:1px solid; width:75vh}
#control{width:75vh;}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150"> 
 <clipPath id="cp">
  <circle id="fullMoon" r="50" cy="75" cx="75"/>
 </clipPath>
 <g clip-path="url(#cp)">
 <rect width="100%" height="100%" />  
 <circle id="moon" r="50" cy="75" cx="175" fill="white" />
 </g>

 <use xlink:href="#fullMoon" fill="none" stroke="black"  />

</svg>

<p><input id="control" type="range" min="0" max="100" value="60" /><span id="output"></span></p>

Answer №3

Example of Moonlight Animation

To create a moon lighting effect, I propose using an animation of a black circle gradually opening and closing like a light circle.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"  viewBox="0 0 73 73" >
<defs>
 <radialGradient id="RadialGrad"
           fx="50%" fy="50%" r="65%"
           spreadMethod="pad">
          <stop offset="0%"   stop-color="#E7D68C" stop-opacity="1"/>
          <stop offset="100%" stop-color="#FFFEED" stop-opacity="1" />
        </radialGradient>

</defs>
<rect width="100%" height="100%" />
<g transform="rotate(-20 35.5 35.5)">
<circle cx="35.5" cy="35.5" r="35" stroke="none"  fill="url(#RadialGrad)" />

 <circle cx="35.5" cy="35.5" r="35" stroke="none" fill="black" >
 
 <animate id="youngMoon" attributeName="cx" values="35.5;-35.5;" begin="1s;oldMoon.end+1s" dur="10s" fill="freeze" />
<animate id="oldMoon" attributeName="cx" values="105;35.5;" begin="youngMoon.end+1s" dur="10s"  fill="freeze" /> 

</circle> 
</g>
</svg>

Answer №4

Is this what you are looking for?

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 110 110" width="100px" height="100px>
    <circle fill="#000" r="50" cy="55" cx="55"/>
    <circle fill="#fff" r="50" cy="55" cx="90"/>
    <circle fill="transparent" r="50" cy="55" stroke="#000" stroke-width="10" cx="55"/>
</svg>

Utilizing Custom CSS variables:

:root{
  --stroke-width: 10;
  --side: 50;
  --gutter: calc(var(--stroke-width) / 2);
  --cx: calc(var(--gutter) + var(--side));
  --percent: calc(15 * 0.02 * var(--side));
  --moon-light: calc(var(--cx) + var(--percent));
}
  
circle{
     cx: var(--cx);
     cy: var(--cx);
     r: var(--side);
}

.moon-percent{
    cx: var(--moon-light);
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 110 110" width="100px" height="100px">
    <circle fill="#000" />
    <circle class="moon-percent" fill="#fff"/>
    <circle fill="transparent" stroke="#000" stroke-width="var(--stroke-width)"/>
</svg>

Answer №5

If you need to find where two circles intersect, you can use this code snippet to draw the corresponding path.

Here is an example of how it works:

requestAnimationFrame(draw);

function draw(t) {
  requestAnimationFrame(draw);
  let r = 51;
  let x = Math.sin(t/2010)*90;
  let y = Math.sin(t/1731)*40;
  let a = Math.atan2(y, x);
  let s = Math.acos(Math.sqrt(x*x + y*y)/2/r);
  let p0 = [Math.cos(a+s)*r, Math.sin(a+s)*r];
  let p1 = [Math.cos(a-s)*r, Math.sin(a-s)*r];
  sun.setAttribute('d', `
      m${p0}
      A${r},${r},0,1,1,${p1}
      A${r},${r},0,0,0,${p0}
      z
  `);
}
body{
  overflow: hidden;
  margin: 0;
}
<svg viewBox=-55,-55,110,110 height=100vh width=100vw>
  <path id=sun stroke=teal fill=none stroke-width=2 stroke-linejoin=round></path>
</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

Creating a visually appealing label by customizing it according to the child div

Can the label be styled based on whether the input is checked or not using CSS, or do I have to use JavaScript? <label class="filterButton"> <input name="RunandDrive" type="checkbox" value="1"> </label> ...

Using Custom .woff Format Fonts in Sendgrid: A Guide

Having trouble with implementing custom fonts in Sendgrid. While Google fonts work fine, the custom .woff format font doesn't seem to cooperate. I've attempted three solutions below. Solution number 1 shows up in the Preview tab but not in the em ...

Can a screenshot of a YouTube video be printed exactly as it appears on a website?

Is there a way to print a page with an embedded YouTube video without it showing up as a blank area? I want the printed version to display the same still shot that appears on the web. If this isn't possible, I will use a noprint stylesheet. Here is ho ...

Tips for adding a CSS class to an HTML element on-the-fly

As a newcomer to JavaScript and AngularJS, my question may be considered naive by some. I am currently working on a tutorial project involving AngularJS. Here is the HTML code snippet I am dealing with: <link href="http://netdna.bootstrapcdn.com/boo ...

How to automatically close the menu on a Wordpress theme after clicking a link

I am currently using a Wordpress theme named ichiban, which can be viewed by following this link. Within this theme, I have created custom menu items that are designed to link directly to different sections on the same page. However, I am encountering an i ...

Create another div for the remaining vertical space occupied by the sibling div?

I currently have 3 different divs nested within each other: <div class="a"> <div class="b"> </div> <div class="c"> </div> </div> Here is the current CSS styling applied to these divs: .a { hei ...

Creating a shadow effect on a mat-card component in Angular

Working on my project that involves an angular frontend, I attempted to add a shadow effect to one of my components by using class="mat-elevation-z8". Strangely, this did not have the desired effect. This is the HTML code in question: <mat-card class= ...

Sliding right is done by activating the Switch Function, while sliding to the left can be achieved by deactivating it with the help

My objective is to create a functionality where flipping the switch button will cause it to slide automatically to the right, revealing a red background div. When switched off, it should return to its original position with a yellow background using Jquery ...

Craft dynamic SVG components using TypeScript

Looking to generate a correctly formatted SVG element using TypeScript: createSVGElement(tag) { return document.createElementNS("http://www.w3.org/2000/svg", tag); } Encountering an issue with tslint: Error message: 'Forbidden http url in str ...

Three-column navigation menu featuring visuals

I'm currently working on the stylesheet for a website and trying to figure out the most effective way to design the navigation menu. Here's how the menu is structured: There are double vertical lines between column 1 and 2, as well as between co ...

Introducing a content height offset to create a smooth slide-up animation on hover

How can I offset a block with a title and description above a picture by the height of the description content? See the example picture below: https://i.sstatic.net/DzcMo.png The goal is to have both titles visible by default, but when hovering over the ...

Tips for creating a vertical navigation submenu with hover using Bootstrap style

How can I create a vertical navigation with sub-menu/widgets using Bootstrap 4.2.1? Here is the requirement: https://i.sstatic.net/JaiLV.jpg My attempt so far: The menu only works onclick, not on mouse over (sub menu still shows when mouse moves out). ...

HTML: A peculiar table setup with an image displayed on the right side and text aligned to the left side. Strangely, the

Just starting out and seeking assistance <table style="border:none" cellpadding="0" cellspacing="0"> <tbody> <tr> <td style="border:none" valign="top" vertical-align:"top"; width="20%"> <div><img class= ...

How can I utilize JavaScript to seamlessly loop through and display these three images in succession?

My current code is HTML, CSS, and JS-based. I am looking to design three of these div elements that appear and hide in a loop every 3-5 seconds. After the first run, I want the execution to repeat continuously. How can I modify my code to achieve this func ...

Ever thought about harnessing the power of SassDoc to create detailed documentation for your sass

After experimenting with sassdoc for documenting our sass mixins and functions, I realized that there doesn't seem to be a straightforward way to generate documentation for our sass variables. Specifically, I am looking for a solution that can output ...

CSS styling not appearing on HTML button

I'm attempting to create a login page similar to Instagram using HTML and CSS. However, I'm having trouble styling the button to match Instagram's login page. The button <input type="submit" class="sub-btn"> The CS ...

How can I eliminate the border from the last child in a row within a responsive framework?

Put simply, I am trying to target not only the last child in a parent div, but also the last item in a row that adjusts based on screen size. I have a row of 4 elements (divs) with borders on all but the last one using :last-child. However, when the screen ...

Angular - when removing items from ngRepeat, the remaining elements do not transition smoothly; instead, they abruptly snap or jump into position

Currently using AngularJS v1.4.8 with ngAnimate injected into my controller. In the process of creating a dynamic list using ngRepeat, tied to an array. The addition and updating of items in the list function smoothly with animations working as intended. ...

Loading screen for specific content section

I currently have a CSS preloader implemented on my WordPress site, but I am facing an issue where the preloader hides the entire page instead of just a part of the content that I want to hide. Specifically, I would like to hide only the main content sectio ...

I am running into issues getting Tailwind CSS to work in my project. Despite following the installation instructions in the documentation and trying to learn this new CSS framework, it doesn't seem to

//I followed the instructions in the tailwind documentation to install and set up everything. However, when I try to use tailwind utility classes in my HTML file, they don't seem to work. Can someone please assist me with this issue? // Here is my sr ...