Fill in overlapping circle area
One way you can approach this is by adding a "inner-cursor" circle inside the main circle. Based on mouse movement it will move with the main cursor given the illusion of overlap.
In this case, the background color of the intersecting circles will not matter. Also, you do not have to worry about mix-blend-mode since the inner cursor has a background color and is hidden. It is only viewed if the mouse hovers over the main circle.
See this example:
$(document).mousemove(function(e) {
// elements
let cursor = $('.cursor');
let innerCursor = $('.inner-cursor');
let c2 = $('.circle');
let pos = {
left: e.pageX - 25,
top: e.pageY - 20
};
cursor.css(pos);
innerCursor.css({
left: pos.left - c2.offset().left,
top: pos.top - c2.offset().top
});
// circles
// radius
var d1 = cursor.outerWidth(true) / 2;
var d2 = c2.outerWidth(true) / 2;
// centers of first circle
var x1 = cursor.offset().left + cursor.width() / 2;
var y1 = cursor.offset().top + cursor.height() / 2;
// centers of second circle
var x2 = c2.offset().left + c2.width() / 2;
var y2 = c2.offset().top + c2.height() / 2;
var i1 = c2.find('.inter1');
var i2 = c2.find('.inter2');
var o = cursor.find('.overlap');
function calc() {
var a = d2;
var b = d1;
var c = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
var d = (b * b + c * c - a * a) / (2 * c);
var h = Math.sqrt((b * b) - (d * d));
// console.log(a, b, c, d, h);
if (d < 0 || $.isNumeric(h)) {
c2.css('border-color', 'red');
} else {
c2.css('border-color', 'black');
}
var x3 = (x2 - x1) * d / c + (y2 - y1) * h / c + x1;
var y3 = (y2 - y1) * d / c - (x2 - x1) * h / c + y1;
var x4 = (x2 - x1) * d / c - (y2 - y1) * h / c + x1;
var y4 = (y2 - y1) * d / c + (x2 - x1) * h / c + y1;
if ($.isNumeric(h)) {
i1.show();
i2.show();
} else {
i1.hide();
i2.hide();
}
i1.offset({
top: y3 - 5,
left: x3 - 5
});
i2.offset({
top: y4 - 5,
left: x4 - 5
});
}
calc();
});
body {
background: #fff;
}
.clip {
display: inline-block;
background: blue;
height: 50px;
width: 50px;
border-radius: 50%;
clip-path: ellipse(50px 50px at 50% 0%);
position: absolute;
left: 750px;
top: 40px;
}
.cursor {
left: 750px;
top: 40px;
}
.cursor {
height: 50px;
width: 50px;
border-radius: 50%;
position: absolute;
pointer-events: none;
z-index: 999;
border: 1px solid black;
outline: 1px solid #c9d3ff;
overflow: none;
mix-blend-mode: multiply;
background: rgba(100, 100, 100, 0.1);
}
.circle {
background: rgba(100, 100, 100, 0.1);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border: 1px solid black;
outline: 1px solid #c9d3ff;
overflow: hidden;
}
.circle::after,
.cursor::after {
display: block;
content: '';
height: 1px;
background: #c9d3ff;
position: absolute;
top: 50%;
left: 0;
right: 0;
}
.circle::before,
.cursor::before {
display: block;
content: '';
width: 1px;
background: #c9d3ff;
position: absolute;
left: 50%;
top: 0;
bottom: 0;
}
.inter {
width: 10px;
height: 10px;
background: black;
border-radius: 50%;
position: absolute;
display: none;
}
.inner-cursor {
height: 50px;
width: 50px;
border-radius: 50%;
position: absolute;
pointer-events: none;
background: green;
left: 50%;
top: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cursor">
</div>
<span class="clip"></span>
<div class="circle">
<div class='inner-cursor'></div>
<div class="inter1 inter"></div>
<div class="inter2 inter"></div>
</div>
On easy idea using only CSS is to consider a radial-gradient
as background using background-attachement:fixed
. You apply this background to the cursor element and you make its dimension/position the same as the fixed element.
All you need to add in your code is:
background:radial-gradient(circle,blue 100px,transparent 100px) fixed no-repeat
I have also optimized the code to remove the line you draw with pseudo element to consider linear-gradient
$(document).mousemove(function(e) {
$('.cursor').eq(0).css({
left: e.pageX - 25,
top: e.pageY - 20
});
// circles
var c1 = $('.cursor');
var c2 = $('.circle');
// radius
var d1 = c1.outerWidth(true)/2;
var d2 = c2.outerWidth(true)/2;
// centers of first circle
var x1 = c1.offset().left + c1.width()/2;
var y1 = c1.offset().top + c1.height()/2;
// centers of second circle
var x2 = c2.offset().left + c2.width()/2;
var y2 = c2.offset().top + c2.height()/2;
var i1 = c2.find('.inter1');
var i2 = c2.find('.inter2');
var o = c1.find('.overlap');
function calc() {
var a = d2;
var b = d1;
var c = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
var d = (b*b+c*c-a*a)/(2*c);
var h = Math.sqrt((b*b) - (d*d));
if (d < 0 || $.isNumeric(h)) {
c2.css('border-color', 'red');
} else {
c2.css('border-color', 'black');
}
var x3 = (x2-x1)*d/c + (y2-y1)*h/c + x1;
var y3 = (y2-y1)*d/c - (x2-x1)*h/c + y1;
var x4 = (x2-x1)*d/c - (y2-y1)*h/c + x1;
var y4 = (y2-y1)*d/c + (x2-x1)*h/c + y1;
if ($.isNumeric(h)) {
i1.show();
i2.show();
} else {
i1.hide();
i2.hide();
}
i1.offset({ top: y3-5, left: x3-5});
i2.offset({ top: y4-5, left: x4-5});
} calc();
});
body {
background: #fff;
margin:0;
}
*{
box-sizing:border-box;
}
.cursor {
height: 50px;
width: 50px;
border-radius: 50%;
position: absolute;
pointer-events: none;
z-index: 999;
border: 1px solid black;
outline: 1px solid #c9d3ff;
background:
linear-gradient(#c9d3ff,#c9d3ff) center/100% 1px,
linear-gradient(#c9d3ff,#c9d3ff) center/1px 100%,
radial-gradient(circle,blue 100px,transparent 101px) fixed,
yellow;
background-repeat:no-repeat;
}
.circle {
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border: 1px solid black;
outline: 1px solid #c9d3ff;
background:
linear-gradient(#c9d3ff,#c9d3ff) center/100% 1px,
linear-gradient(#c9d3ff,#c9d3ff) center/1px 100%,
#f2f2f2;
background-repeat:no-repeat;
}
.inter {
width: 10px;
height: 10px;
background: black;
border-radius: 50%;
position: absolute;
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cursor">
</div>
<div class="circle">
<div class="inter1 inter"></div>
<div class="inter2 inter"></div>
<div>
And if the circle is not in the middle you simply adjust the position.
$(document).mousemove(function(e) {
$('.cursor').eq(0).css({
left: e.pageX - 25,
top: e.pageY - 20
});
// circles
var c1 = $('.cursor');
var c2 = $('.circle');
// radius
var d1 = c1.outerWidth(true)/2;
var d2 = c2.outerWidth(true)/2;
// centers of first circle
var x1 = c1.offset().left + c1.width()/2;
var y1 = c1.offset().top + c1.height()/2;
// centers of second circle
var x2 = c2.offset().left + c2.width()/2;
var y2 = c2.offset().top + c2.height()/2;
var i1 = c2.find('.inter1');
var i2 = c2.find('.inter2');
var o = c1.find('.overlap');
function calc() {
var a = d2;
var b = d1;
var c = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
var d = (b*b+c*c-a*a)/(2*c);
var h = Math.sqrt((b*b) - (d*d));
if (d < 0 || $.isNumeric(h)) {
c2.css('border-color', 'red');
} else {
c2.css('border-color', 'black');
}
var x3 = (x2-x1)*d/c + (y2-y1)*h/c + x1;
var y3 = (y2-y1)*d/c - (x2-x1)*h/c + y1;
var x4 = (x2-x1)*d/c - (y2-y1)*h/c + x1;
var y4 = (y2-y1)*d/c + (x2-x1)*h/c + y1;
if ($.isNumeric(h)) {
i1.show();
i2.show();
} else {
i1.hide();
i2.hide();
}
i1.offset({ top: y3-5, left: x3-5});
i2.offset({ top: y4-5, left: x4-5});
} calc();
});
body {
background: #fff;
margin:0;
}
*{
box-sizing:border-box;
}
.cursor {
height: 50px;
width: 50px;
border-radius: 50%;
position: absolute;
pointer-events: none;
z-index: 999;
border: 1px solid black;
outline: 1px solid #c9d3ff;
background:
linear-gradient(#c9d3ff,#c9d3ff) center/100% 1px,
linear-gradient(#c9d3ff,#c9d3ff) center/1px 100%,
radial-gradient(circle at 20% 50%,blue 100px,transparent 101px) fixed
yellow;
background-repeat:no-repeat;
}
.circle {
border-radius: 50%;
position: absolute;
top: 50%;
left: 20%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border: 1px solid black;
outline: 1px solid #c9d3ff;
background:
linear-gradient(#c9d3ff,#c9d3ff) center/100% 1px,
linear-gradient(#c9d3ff,#c9d3ff) center/1px 100%,
#f2f2f2;
background-repeat:no-repeat;
}
.inter {
width: 10px;
height: 10px;
background: black;
border-radius: 50%;
position: absolute;
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cursor">
</div>
<div class="circle">
<div class="inter1 inter"></div>
<div class="inter2 inter"></div>
<div>
We basically use the same value of top/left to have the following:
radial-gradient(circle at [left] [top],blue [radius],transparent [radius]);
I add 1px
to transparent to avoid the jagged edge