Getting canvas path from div outline or border - javascript

I am trying to create a poker table with dots around the table to represent players. The image you can see below represents what I have done already and gives the general idea of what I want but, as you can see the dots (players) are not distributed equally. Is it possible to get the path value along the outer part of the table below and then iterate the 'chips' along it?
export default function PokerTable() {
return (
<div className='poker-table'>
{
[...Array(10)].map((index, key) =>(
<div className='player' key={key}>
</div>
))
}
</div>
)
}
.poker-table {
width: 40%;
height: 60%;
background-color: #4aad4a;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
border-radius: 150px;
position: relative;
border: 15px solid #C0C0C0;
&:before {
content: "";
display: block;
width: 100%;
height: 100%;
border-radius: 150px;
position: absolute;
top: -15px;
left: -15px;
}
&:after {
content: "";
display: block;
width: 100%;
height: 100%;
border-radius: 130px;
position: absolute;
top: 0;
left: 0;
}
}
.player{
width: 30px;
height: 30px;
border-radius: 50%;
position: absolute;
transform: translate(-50%, -50%);
border: 3px solid black;
&:nth-child(1) {
top: 0;
left: 50%;
background-color: red;
}
&:nth-child(2) {
top: 15%;
left: 95%;
background-color: yellow;
}
&:nth-child(3) {
top: 50%;
left: 100%;
background-color: green;
}
&:nth-child(4) {
top: 85%;
left: 95%;
background-color: rgb(38, 0, 128);
}
&:nth-child(5) {
top: 100%;
left: 50%;
background-color: rgb(128, 0, 100);
}
&:nth-child(6) {
top: 85%;
left: 5%;
background-color: rgb(90, 128, 0);
}
&:nth-child(7) {
top: 50%;
left: -2%;
background-color: rgb(0, 128, 122);
}
&:nth-child(8) {
top: 15%;
left: 5%;
background-color: rgb(26, 26, 10);
}
&:nth-child(9) {
top: 4%;
left: 22%;
background-color: rgb(133, 133, 133);
}
&:nth-child(10) {
top: 97%;
left: 75%;
background-color: rgb(106, 76, 179);
}
}

This answer takes a step back to consider a basic problem which has not been mentioned in the question.
There are problems if the table shape is defined in terms of percentage width and height of the viewport.
On different devices the table with have different aspect ratios. This could be overcome by always placing the table inside a container with fixed aspect ratio.
However, even then the table will look different on different container/viewport widths because the border radius has been defined in absolute (px) terms.
Basically, to have a consistent table shape you cannot mix relative and absolute units
This snippet defines the table purely in terms of its width, which in this example is set at 40vmin (if you use vmin you know it will always fit in the viewport). Everything else is calculated in relation to that using CSS variables and its calc function.
body {
width: 100vw;
height: 100vh;
position: relative;
}
.poker-table {
--w: 40vmin;
--h: calc(var(--w) * 60 / 40);
width: var(--w);
height: var(--h);
background-color: #4aad4a;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
--br: calc(var(--w) / 2); /* border radius */
border-radius: var(--br);
position: relative;
--bw: calc(var(--w) / 20); /* border (the gray bit) width */
border: var(--bw) solid #C0C0C0;
box-sizing: content-box;
margin: 0;
padding: 0;
}
<div class='poker-table'>
</div>
Now to find the left and top positions (in CSS) terms where the player must be placed to ensure they are equally spaced around the table we need to do a bit of geometry.
In the above snippet the radius of the top and bottom of the table was chosen deliberately to make the calculation a bit easier. The border radius was defined as half the table width. So the parts of a circle which CSS uses to know where to paint are like in this picture:
And the entire length of the edge of the table is 2*PI*br + (2*h-2*br) - the circumference of the circle (i.e. the 4 arcs in the corners) plus what remains of the height twice (the two straight edges).
The players need to be spaced around so the distance between them is one tenth of this length.
It's now a question of doing a bit of math to calculate the angle sub-tended by the second player, for example, and hence its left and top coordinates, then move onto the second player. Let me know if you need help with this - but it's stopped being HTML/CSS and gone on to be geometry!

Related

Stretch divs based on wrapper AND on window positions without JS

The following image will be helpful.
Consider a traditional centered wrapper with max-width.
Then wrapper has 2 columns using 40% and 60% of the wrapper respectively (random number that isn't 50%).
Is there a way to stretch the divs outter limit to match the window borders without Javascript - while the inner limits respect the wrapper reference?
This unfortunatelly doesn't work:
#div1{
left: 0vw;
right: 40%; /*of .wrapper */
}
#div2{
left: 40%; /*of .wrapper */
right: 100vw;
}
Solution with JS (poorly written): https://jsfiddle.net/sirojuntle/ktvap86c/12/
The idea is to make smaller desktop layout looks better in larger screens.
Thanks
Because your wrapper is position: relative; half your job is already done. Even with position: absolute; your divs still take the wrapper as their parent co-ordinates.
With that in mind, it's easier than you think.
.div1{
right: 60%; /* is 40% from the left, like your picture */
left: calc(50% - 50vw)
}
.div2{
left: 40%;
right: calc(50% - 50vw)
}
You can play with negative margin
.wrapper {
--m: min(0px, (800px - 100vw)/2);
}
.row1 {
width: calc(40% - var(--m));
margin-left: var(--m);
}
.row2 {
width: calc(60% - var(--m));
margin-right: var(--m);
margin-left:auto;
}
Full code:
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
}
.wrapper {
--m: min(0px, (800px - 100vw)/2);
border: 3px solid pink;
max-width: 800px;
background-size: 10%;
background-image: linear-gradient(90deg, #000, #0000 5%);
margin:auto;
}
.row1 {
background-color: red;
min-height: 100px;
width: calc(40% - var(--m));
margin-top: 20px;
margin-bottom: 20px;
margin-left: var(--m);
}
.row2 {
background-color: darkred;
width: calc(60% - var(--m));
margin-left:auto;
margin-right: var(--m);
min-height: 100px;
}
<div class="wrapper" id="wrapper">
<div class="row1" id="ref">
There is a way to stretch this with CSS?
</div>
<div class="row2" id="ref2">
And that?
</div>
</div>

Percentage circle border CSS React [duplicate]

This question already has answers here:
Percent pie chart with css only
(3 answers)
Closed 1 year ago.
I try to create a circle with a border in which I can control the ratio of the red part to the green part. I am using React and styled-components. I created something like this:
import React from "react";
import styled from "styled-components";
const Wrapper = styled.div`
margin: 50px auto;
width: 150px;
height: 150px;
background: ${({ theme }) => theme.red};
border-radius: 50%;
`;
const Circle = styled.div``;
const MaskFull = styled.div`
width: 150px;
height: 150px;
position: absolute;
border-radius: 50%;
clip: rect(0px, 150px, 150px, 75px);
animation: fill ease-in-out 3s;
transform: rotate(126deg);
`;
const Fill = styled.div`
clip: rect(0px, 75px, 150px, 0px);
background-color: ${({ theme }) => theme.green};
animation: fill ease-in-out 3s;
transform: rotate(126deg);
width: 150px;
height: 150px;
position: absolute;
border-radius: 50%;
`;
const InsideCircle = styled.div`
width: 130px;
height: 130px;
border-radius: 50%;
background: #fff;
line-height: 130px;
text-align: center;
margin-top: 10px;
margin-left: 10px;
position: absolute;
z-index: 100;
font-weight: 700;
font-size: 2em;
`;
const SecondMask = styled.div`
width: 150px;
height: 150px;
position: absolute;
border-radius: 50%;
clip: rect(0px, 150px, 150px, 75px);
`;
const Avatar: React.FC = () => {
return (
<Wrapper>
<Circle>
<MaskFull>
<Fill />
</MaskFull>
<SecondMask>
<Fill />
</SecondMask>
<InsideCircle />
</Circle>
</Wrapper>
);
};
export default Avatar;
but as you can see on the picture, there is an ugly 1px protruding red fragment. I can't find the bug in my code, how can I fix it?
Is don't think it's particularly a bug in your code - it's just that the system is trying to work out how to show part CSS pixels on a screen which uses several screen pixels per CSS pixel. Some can get 'left behind'.
A different way of creating the effect you want is to use background images made up of a conic gradient overlaid with a radial one (to give the 'hole' in the middle).
This is a simple snippet to demonstrate the idea in HTML/CSS. The CSS variable --ratio could be set in JS using setProperty to whatever the ratio of red to green is required.
.ratio {
--ratio: 0.3;
height: 150px;
width: 150px;
border-radius: 50%;
position: relative;
clip-path: circle(50%);
}
.ratio::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: conic-gradient(red 0 calc(var(--ratio) * 360deg), lime calc(var(--ratio) * 360deg) 360deg);
z-index: -2;
}
.ratio::after {
content: '';
position: absolute;
width: 80%;
height: 80%;
top: 10%;
left: 10%;
background-color: white;
border-radius: 50%;
z-index: -1;
}
<div class="ratio"></div>
Note: while it is possible to get the same effect using a simpler set up - just one background-image statement on the actual div with first the radial gradient and then the conic gradient you can run into another 'pixel' problem, a sort of fuzziness around the curves. Hence this snippet tidies the circles up with clip-path to give smooth edges.

css/JavaScript resize div content to fit window

I have a page with a lot of images positioned on top of another image.
The position of the smaller images is relative, and the left and top distance is given using px.
When I scale the window, the collection of images moves and stays in the right place. But I want it to also scale when I resize the window. (The ratio of the images should stay the same, but smaller/larger.)
All the images are contained in an overlaying div.
Is there any way for me to do this without having to reposition all the images? (I'm very new to css/JavaScript)
Here's an example of what is happening: https://codepen.io/gwenvere/pen/MWJdvJp
What I want is for the red ball to stay on top of the mountain, but for the mountain and ball to shrink if the window becomes smaller.
Here is an example of the css of one of the smaller images:
position: relative;
left: 161.7px;
top: 208.7px;
width: 79px;
height: 79px;
background-color: rgba(56, 152, 236, 0);
background-image: url('../images/Medium.png');
background-position: 0px 0px;
background-size: cover;
}
The css of the larger image:
.image-11 {
position: absolute;
left: 0%;
top: 148px;
right: 0%;
bottom: 0%;
width: 1200px;
max-width: 1200px;
margin-top: -37px;
margin-right: auto;
margin-left: auto;
}
css of the overlaying div:
.div-block-3 {
position: relative;
width: 1200px;
height: 800px;
max-height: none;
max-width: none;
min-height: auto;
min-width: auto;
margin-right: auto;
margin-left: auto;
background-color: rgba(83, 39, 39, 0);
-webkit-transform-origin: top left;
}
The image in your Codepen is set to position: absolute at a fixed width and height of 1200px and 800px, so it doesn’t resize.
As your description of your question talks about resizing the window, I’m assuming you want your main image to scale up and down and for the red dot to stay in the same relative position.
One way to do it using CSS would be to use percentages of the width and height to position the red dot, and use a percentage of the width to scale the size of the dot (using a ratio to set the dot’s height.
body {
padding: 0;
margin: 0;
}
.body {
position: relative;
width: 100%;
max-width: 1200px;
margin-top: 147px;
margin-right: auto;
margin-left: auto;
background-color: rgba(83, 39, 39, 0);
}
.largeImage {
width: 100%;
height: auto;
}
.smallImage {
display: block;
position: absolute;
left: 57.5%;
top: 26.17%;
width: 6.67%;
height: auto;
transform: translate(-50%,50%);
background-color: rgba(56, 152, 236, 0);
background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Circle_Burgundy_Solid.svg/1024px-Circle_Burgundy_Solid.svg.png");
background-position: 0px 0px;
background-size: cover;
margin: 0 auto;
}
.smallImage::before {
display: block;
padding-top: 100%;
content: "";
}
.smallImage a {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
<div class="body">
<img src="https://media.sproutsocial.com/uploads/2017/02/10x-featured-social-media-image-size.png" loading="lazy" alt="" class="largeImage">
<div class="smallImage">
</div>
</div>
I included a margin above the image as you had that in your Codepen.

CSS Scaled Div Centring

I am having an issue centring a <div id='divTwo'> inside another <div id='divOne'>. This is normal an easy thing to do, however in this instance i have transform: scale(); with transform-origin: 50% 50% 0px; applied on 'divTwo'
#divOne {
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}
#divTwo {
width: 1024px;
height: 768px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
border-left: 131px solid #333333;
border-right: 131px solid #333333;
border-top: 47.5px solid #333333;
border-bottom: 47.5px solid #333333;
border-radius: 55px;
}
if the scale applied to the transform and the window is larger than the outerWidth(), 'divTwo' has no issue centring. However when the 'divTwo' is scaled and the window is smaller or equal to the outerWidth(). The div will no longer centre, instead it will place its centre point to be right side of the browser, resulting if half the of 'divTwo' being off the right hand-side of the browser. Changing transform-origin: 50% 50% 0px; to transform-origin: 0% 50% 0px; works so long as you don't scale vertically, and vice versa.
jsfiddle example : https://jsfiddle.net/yvyz49zp/
Thank you. I feel like am missing something of obvious.
I knocked this up relatively quickly in jsfiddle - no javascript needed. Just play around with the values until you get something you like.
Code:
body {
background: lightblue;
}
#container {
display: inline-block;
position: absolute;
width: 50%;
right: 50%;
top: 50%;
transform: translate(50%, -50%);
}
#dummy {
margin-top: 75%; /* Using the dummy is the trick - it locks the aspect ratio (at 4:3 in this case) */
}
#device {
position: absolute;
top: 10%;
bottom: 10%;
left: 0;
right: 0;
background-color: #333;
border-radius: 10%;
}
#screen {
position: absolute;
width: 70%;
height: 80%;
background: #0f0;
right: 50%;
top: 50%;
transform: translate(50%, -50%);
}
<div id="container">
<div id="dummy"></div>
<div id="device">
<div id="screen"></div>
</div>
</div>

Pure JavaScript: Center an absolute position div in body

What's the easiest and shortest way to center an absolute position div in the body without using a library like jQuery. Thank you!
Edit:
Something like http://jsfiddle.net/apfwh/ but maybe with a bit cleaner?
I think no js needed. CSS will do it (see here):
body {
background: #888;
}
.box {
width: 100px;
height: 100px;
background: #ccc;
position: absolute;
left: 50%;
top: 50%;
margin: -50px 0 0 -50px;
}
UPD
In case you don't have fixed width/height of element:
JS (when element is opened):
element.style.margitLeft = -element.offsetWidth / 2
element.style.margitTop = -element.offsetHeight / 2
CSS:
.box {
background: #ccc;
position: fixed;
left: 50%;
top: 50%;
}

Categories