让我们来画(椭)圆~

296 阅读2分钟

最近项目需求,需要绘制一个圆球,两个相同圆心的椭圆,用以对应视频区域上的范围,会应用到一点点有趣的css知识,给大家分享一下。

思路

1,建议以画椭圆的方式去画圆,不要相信狗 * 品的花言巧语,都是骗纸!

2,画椭圆有两种思路,建议选择思路二(直接画)

思路一. 画一个圆,然后用3D旋转来让他变成椭圆;

会出现两个问题
1,3D旋转会导致边框变成 dash 一样的形式, 有锯齿! 这点和拿图片进行3D旋转一样
2,画出来的椭圆范围,难以控制其与目标区域对应。

思路二. 直接画椭圆 border-radius: 50%;,宽高比不是1:1 即可画出椭圆。

3,多个椭圆组合成球、双椭圆重叠区域等需求实现时,建议优先考虑直接上定位!

先画两个简单的椭圆

html

<div class="circle circle-ps"></div>
<div class="circle-in circle-in-ps"></div>

css

.circle{
  width: 200px;
  height: 200px;
  border-radius: 50%;
  border: 1px solid rgba(253,73,84, 1);
  box-shadow: inset 0 0 40px 0 rgba(253,73,84, 0.5);
    margin-bottom: 20px;
}

.circle-in{
    width: 200px;
    height: 50px;
    border-radius: 50%;
    border: 1px solid rgba(253,73,84, 1);
    box-shadow: inset 0 0 40px 0 rgba(253,73,84, 0.5);
    margin-bottom: 20px;
}

image.png

image.png

组合成球

css

.circle-ps, .circle-in-ps{
    position: absolute;
    left: 200px;
    top: 200px;
    transform: translate(-50%, -50%);
}

image.png

组成相同圆心的椭圆

<div class="circle-oval"></div>
<div class="circle-in-oval"></div>
.circle-oval{
    width: 400px;
    height: 100px;
    border-radius: 50%;
    border: 1px solid rgba(59,194,133,1);
    box-shadow: inset 0 0 40px 0 rgba(59,194,133,.5);
    margin-bottom: 20px;
}
.circle-in-oval{
    width: 300px;
    height: 50px;
    border-radius: 50%;
    border: 1px solid rgba(255,185,74,1);
    box-shadow: inset 0 0 40px 0 rgba(255,185,74, .5);
    margin-bottom: 20px;
}

.circle-oval, .circle-in-oval{
    position: absolute;
    left: 400px;
    top: 400px;
    transform: translate(-50%, -50%);
}

image.png

让我们用vue3封装一下

Circle/index.vue

<template>
  <div
    class="circle"
    :style="{
        width: longD + 'px',
        height: (shotD || longD) + 'px',
        border: `1px solid rgba(${rgbColor}, 1)`,
        'box-shadow': `inset 0 0 100px 0 rgba(${rgbColor})`,
        position: centerLongLat && centerLongLat.length === 2 ? 'absolute' : 'static',
        left: centerLongLat && ( centerLongLat[0] + 'px' ),
        top: centerLongLat && ( centerLongLat[1] + 'px' ),
        transform: centerLongLat ? 'translate(-50%, -50%)': 'none'
      }"
  >
    <slot></slot>
  </div>
</template>

<script setup lang="ts">
defineProps<{
  centerLongLat?: number[] | undefined, // 圆心位置
  longD: number; // 长直径
  shotD?: number; // 短直径。没传则默认和 width 一致
  rgbColor: string; // 圆的颜色
}>()

</script>
<style scoped>
.circle{
  border-radius: 50%;
  outline:1px solid transparent;
}
</style>

使用示例

<Circle
  class="circle"
  v-if="sphere.longLat.length > 0 && sphere.longD && sphere.shotD"
  :rgb-color="sphere.rgbColor"
  :long-d="sphere.longD"
  :shot-d="sphere.shotD"
  :center-long-lat="sphere.longLat"
/>
const sphere = ref({
  longLat: [],
  longD: 0, // 内外圆公用长边
  shotD: 0,  // 外圆短边
  rgbColor: '253,73,84, 1'
})

完结~