Reputation: 55
EDIT 1: Quick codepen of my current issue: https://codepen.io/zuffdaddy/pen/QWGewKr See how the clip path is massive while the image is small? How do align those two?
Original:
Intro: I'm making an Attack Disc for a submarine simulator game.
The disc has multiple circular rings that all rotate and so far I have that part complete, but there's some overlapping transparent plastic parts that sit on top the rings and rotate as well.
Problem: The problem is the plastic pieces that rotate on top are complex shapes (image of the shape here). The user needs to be able to click around them to manipulate the rings beneath them but also be able to click on them to rotate them as well.
SVG Clipping paths seem to be the way to go but I cannot get the svg clip path to align with the image.
Please ignore the JS, it's a temporary rotating script I pulled from another question here and will be rewritten towards finalization.
///////////////////////////////
// ------- rotate -------- //
///////////////////////////////
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('attack_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('course_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('aob_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('bearing_lead_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
html {
height: 100%;
overflow: hidden;
}
body {
background: #1c1c1c;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.wrapper {
height: 100%;
max-height: 960px;
width: 100%;
max-width: 960px;
position: relative;
margin: auto;
}
#attack_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/1.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 30vw;
max-width: 1124px;
height: 30vw;
max-height: 1124px;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
transform-origin: 50% 50%;
border-radius: 50%;
}
#course_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/2.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 23vw;
max-width: 868px;
height: 23vw;
max-height: 868px;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
transform-origin: 50% 50%;
border-radius: 50%;
}
#aob_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/3.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 15.5vw;
max-width: 592px;
height: 15.5vw;
max-height: 592px;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
transform-origin: 50% 50%;
border-radius: 50%;
}
#bearing_lead_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/4.png');
background-size: cover;
background-repeat: no-repeat;
background-position: center;
width: 23.5vw;
max-width: 884px;
height: 23.5vw;
max-height: 884px;
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
clip-path: url('#my-clip-path');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="attack_disc"></div>
<div id="course_disc"></div>
<div id="aob_disc"></div>
<div id="bearing_lead_disc">
<svg class="svg">
<clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="M0.501,0 C0.556,0,0.555,0.04,0.555,0.04 C0.555,0.099,0.984,0.229,0.994,0.232 S1,0.243,0.999,0.251 C0.976,0.284,0.874,0.421,0.656,0.469 C0.656,0.469,0.648,0.47,0.647,0.474 C0.646,0.48,0.572,0.984,0.57,0.992 C0.569,0.996,0.569,0.999,0.561,0.999 C0.522,1,0.516,1,0.502,1 C0.487,1,0.482,1,0.443,0.999 C0.434,0.999,0.434,0.996,0.433,0.992 C0.432,0.984,0.358,0.48,0.357,0.474 C0.356,0.47,0.347,0.469,0.347,0.469 H0.347 C0.129,0.421,0.027,0.284,0.005,0.251 C0,0.243,0,0.236,0.01,0.232 S0.449,0.099,0.449,0.04 C0.449,0.04,0.447,0,0.502,0"></path></clipPath>
</svg>
</div>
</div>
Upvotes: 2
Views: 1310
Reputation: 101956
The problem appears to be that you extracted the shape and converted it to objectBoundingBox
coordinates relative to itself. So the objectBoundingBox coords are no longer relative to your attack disc image.
What you can do is apply a transform to the clip path to scale it down to where it should be. By trial and error I worked out an appropriate scaling that gets it to match the shape it is supposed to clip.
transform="translate(0.5,1) scale(0.415,0.52) translate(-0.5,-1)"
.svg {
position: absolute;
width: 0;
height: 0;
}
.clipped {
width: 884px;
height: 884px;
background: turquoise url(https://zuffdaddy.github.io/uboat-attack-disc/images/4.png);
background-size: cover;
-webkit-clip-path: url(#my-clip-path);
clip-path: url(#my-clip-path);
}
<svg class="svg">
<clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="M0.501,0 C0.556,0,0.555,0.04,0.555,0.04 C0.555,0.099,0.984,0.229,0.994,0.232 S1,0.243,0.999,0.251 C0.976,0.284,0.874,0.421,0.656,0.469 C0.656,0.469,0.648,0.47,0.647,0.474 C0.646,0.48,0.572,0.984,0.57,0.992 C0.569,0.996,0.569,0.999,0.561,0.999 C0.522,1,0.516,1,0.502,1 C0.487,1,0.482,1,0.443,0.999 C0.434,0.999,0.434,0.996,0.433,0.992 C0.432,0.984,0.358,0.48,0.357,0.474 C0.356,0.47,0.347,0.469,0.347,0.469 H0.347 C0.129,0.421,0.027,0.284,0.005,0.251 C0,0.243,0,0.236,0.01,0.232 S0.449,0.099,0.449,0.04 C0.449,0.04,0.447,0,0.502,0" transform="translate(0.5,1) scale(0.415,0.52) translate(-0.5,-1)"></path></clipPath>
</svg>
<div class="clipped"></div>
Upvotes: 2
Reputation: 3496
Svg better to be inside div so you have more control on the shape and it's also can be scale.
First I fix your path 'd' with this site (https://aydos.com/svgedit/)
Second I put the svg inside the div
Third I order the svg with view box to suitable (with color red some transparent) like the background-image link in 'bearing_lead_disc' and use css pointer-events:none for ignore clicking on the div and then we can rotate the circles even we clicked on the shape.
link: (https://codepen.io/omergal/pen/qBqzeQa)
///////////////////////////////
// ------- rotate -------- //
///////////////////////////////
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('attack_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('course_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('aob_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
(function() {
var init, rotate, start, stop,
active = false,
angle = 0,
rotation = 0,
startAngle = 0,
center = {
x: 0,
y: 0
},
R2D = 180 / Math.PI,
rot = document.getElementById('bearing_lead_disc');
init = function() {
rot.addEventListener("mousedown", start, false);
$(document).bind('mousemove', function(event) {
if (active === true) {
event.preventDefault();
rotate(event);
}
});
$(document).bind('mouseup', function(event) {
event.preventDefault();
stop(event);
});
};
start = function(e) {
e.preventDefault();
var bb = this.getBoundingClientRect(),
t = bb.top,
l = bb.left,
h = bb.height,
w = bb.width,
x, y;
center = {
x: l + (w / 2),
y: t + (h / 2)
};
x = e.clientX - center.x;
y = e.clientY - center.y;
startAngle = R2D * Math.atan2(y, x);
return active = true;
};
rotate = function(e) {
e.preventDefault();
var x = e.clientX - center.x,
y = e.clientY - center.y,
d = R2D * Math.atan2(y, x);
rotation = d - startAngle;
return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)";
};
stop = function() {
angle += rotation;
return active = false;
};
init();
}).call(this);
html {
height: 100%;
overflow: hidden;
}
body {
background: #1c1c1c;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.wrapper {
height: 100%;
max-height: 960px;
width: 100%;
max-width: 960px;
position: relative;
margin: auto;
}
#attack_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/1.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 30vw;
max-width: 1124px;
height: 30vw;
max-height: 1124px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
transform-origin:50% 50%;
border-radius:50%;
}
#course_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/2.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 23vw;
max-width: 868px;
height: 23vw;
max-height: 868px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
transform-origin:50% 50%;
border-radius:50%;
}
#aob_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/3.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 15.5vw;
max-width: 592px;
height: 15.5vw;
max-height: 592px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
transform-origin:50% 50%;
border-radius:50%;
}
#bearing_lead_disc {
background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/4.png');
/* background-color: red; */
background-size: contain;
background-repeat: no-repeat;
background-position: center;
width: 23.5vw;
max-width: 884px;
height: 23.5vw;
max-height: 884px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
clip-path: url('#myPath');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="attack_disc"></div>
<div id="course_disc"></div>
<div id="aob_disc"></div>
<div id="bearing_lead_disc" style="pointer-events:none;">
<svg viewBox="0 0 512 512" style="width:100%; height:100%;">
<path style="pointer-events:all;" fill="#ff00004d" d="M255.77 26.76c20 0 19.5 18.5 19.5 18.5 0 27 155.5 86.5 159 88s3.61 5.03 1.78 8.5c-8.07 15.27-45.11 77.9-124.18 99.85 0 0-3.05.81-3.32 2.67-.38 2.6-27.27 233.45-27.88 237.47-.27 1.76-.27 2.84-3.35 2.97-14.18.56-16.1.53-21.37.53s-7.19.03-21.37-.53c-3.08-.12-3.09-1.2-3.35-2.97-.61-4.03-27.5-234.88-27.88-237.47-.27-1.86-3.32-2.69-3.32-2.69-79.01-21.98-116.01-84.57-124.08-99.84-1.83-3.47-1.72-7 1.78-8.5s159-61 159-88c0 0-.5-18.5 19.5-18.5" />
</svg>
</div>
</div>
Upvotes: 2