最近跟合成自定义图片杠上了,总是在搞这些无聊的事,之前文字环形分布是用svg解决的,但是图片环形分布就呵呵了。于是做了些折腾:
SVG:
offset-path 能实现环形分布,实现成本最低,可以直接在客户端转化图片,精确度高,但是浏览器支持度惨不忍睹:
如果无视兼容性推荐这个:具体实现如下:
<style>
@supports (offset-path: path('M0,0 C100,100 700,200 800,100')) {
.box {
width: 500px;
height: 500px;
border: 0px dotted cyan;
position: relative;
transform-style: preserve-3d;
transform: var(--transform);
--transform: scale(1);
display: none;
}
.item{
position: absolute;
motion-offset: 0%;
offset-path: path('M 155 155 m -155 0 a 155 155 0 0 0 310 0 a 155 155 0 0 0 -310 0');
}
}
</style>
<div class="box">
<span class="item"><img src="images/1-t1.png" alt=""></span>
<span class="item"><img src="images/1-t2.png" alt=""></span>
<span class="item"><img src="images/1-t3.png" alt=""></span>
<span class="item"><img src="images/1-t4.png" alt=""></span>
<span class="item"><img src="images/1-t5.png" alt=""></span>
<span class="item"><img src="images/1-t6.png" alt=""></span>
<span class="item"><img src="images/1-t7.png" alt=""></span>
<span class="item"><img src="images/1-t8.png" alt=""></span>
<span class="item"><img src="images/1-t9.png" alt=""></span>
<span class="item"><img src="images/1-t10.png" alt=""></span>
</div>
<script>
let flags = Array.from(strand.querySelectorAll('.flag'));
flags.forEach((flag, i) => {
flag.style.offsetDistance = `${80 + i * 740 / flags.length}px`;
});
</script>
Transform:
兼容性可以,成本也很低,无法在客户端直接转化图片,位置,半径不太好精确控制,实现如下:
<style>
#list {
height: 500px;
width: 500px;
position: relative;
margin:0;padding: 0;
}
.list-item {
list-style: none;
height: 56px;
width: 56px;
position: absolute;
top: 50%;
left: 50%;
}
.canvas{width: 500px;height: 500px;position:absolute; top:0;left:1000px;}
</style>
<div class="canvas">
<ul id="list"></ul>
<button id="add-item">Add item</button>
</div>
<script>
var list = $("#list"),
start = 180;
var updateLayout = function(listItems) {
for (var i = 0; i < listItems.length; i++) {
var offsetAngle = 360 / listItems.length;
var rotateAngle = offsetAngle * i + start-listItems.length*offsetAngle/2;
$(listItems[i]).css({"transform": "rotate(" + rotateAngle + "deg) translate(0, -200px)"})
};
};
$(document).on("click", "#add-item", function() {
var listItem = $("<li class='list-item'><img src='images/1-t1.png' alt=''><button class='remove-item'>Remove</button></li>");
list.append(listItem);
var listItems = $(".list-item");
updateLayout(listItems);
});
$(document).on("click", ".remove-item", function() {
$(this).parent().remove();
var listItems = $(".list-item");
updateLayout(listItems);
});
</script>
绝对定位+rotate
兼容性可以,实现成本比较高,无法在客户端直接转化图片,位置,半径能精确控制,实现如下:
<style>
.hangItem{width: 56px;position: absolute;-webkit-transition: all 1s;}
.canvas{width:500px;height:500px;position:relative;}
</style>
<div class="canvas">
<div id="box">
<div class="hangItem empty">
<img src="images/empty.png" alt="">
</div>
<div class="hangItem">
<img src="images/1-t1.png" alt="">
</div>
<div class="hangItem">
<img src="images/1-t2.png" alt="">
</div>
<div class="hangItem">
<img src="images/1-t3.png" alt="">
</div>
<div class="hangItem">
<img src="images/1-t4.png" alt="">
</div>
<div class="hangItem">
<img src="images/1-t5.png" alt="">
</div>
<div class="hangItem">
<img src="images/1-t5a.png" alt="">
</div>
<div class="hangItem">
<img src="images/1-t5b.png" alt="">
</div>
</div>
</div>
<script>
var circle = document.getElementById('box'),
imgs = $('.hangItem'),
total = imgs.length,
coords = {},
diam,radius1,radius2,imgW;
diam = parseInt(window.getComputedStyle(circle).getPropertyValue('width')),
radius = diam / 2,
imgW = imgs[0].getBoundingClientRect().width,
radius2 = radius - imgW;
var i,
alpha = Math.PI / 2,
len = imgs.length,
corner = 2 * Math.PI / total;
var offsetAngle = 360 / len,
start = 180;
for (i = 0; i < total; i++) {
imgs[i].style.left = parseInt(radius - imgW / 2 + radius2 * Math.cos(alpha)) + 'px';
imgs[i].style.top = parseInt(radius - imgW / 2 - radius2 * Math.sin(alpha)) + 'px';
var rotateAngle = offsetAngle * i + len*offsetAngle/2;
$(imgs[i]).css("transform", "rotate(" + rotateAngle + "deg)");//console.log(rotateAngle);
alpha = alpha - corner;
}
</script>
Canvas
兼容性可以,实现成本比较高,可以在客户端直接转化图片,位置,半径好精确控制,实现如下:
<canvas id="cvs2" width="440" height="440" style="position:absolute;z-index:10;top:38px;left:26px;display: block;">
Your browser not support canvas!
</canvas>
<script>
var cvs2 = document.getElementById("cvs2");
var items = [
"images/empty.png",
"images/1-t5.png",
"images/1-t11.png",
"images/1-t5.png",
"images/1-t10.png",
"images/1-t1.png",
];
function rendItem(ctx,items,radius,itemWidth){
if(items<1) return;
var total = items.length,
radius2 = radius - itemWidth;
var i,
alpha = Math.PI / 2,
corner = 2 * Math.PI / total;
var offsetAngle = 360 / total;
for (i = 0; i < total; i++) {
var itemObj = new Image();
itemObj.src = items[i];
itemObj.onload = function(){
var itemLeft = parseInt(radius - itemWidth / 2 + radius2 * Math.cos(alpha)),
itemTop = parseInt(radius - itemWidth / 2 - radius2 * Math.sin(alpha)),
rotateAngle = (offsetAngle * this.index + total*offsetAngle/2) * Math.PI / 180;//offsetAngle * this.index + total*offsetAngle/2;
ctx.save();
ctx.translate(itemLeft + this.width / 2, itemTop+ this.height / 2);
ctx.rotate(rotateAngle);
ctx.drawImage(this, 0, 0,this.width,this.height,-.5*this.width,-.5*this.height,this.width,this.height);
ctx.translate(-(itemLeft + this.width / 2), -(itemTop+ this.height / 2));
ctx.restore();
alpha = alpha - corner;
}
itemObj.index = i;
}
}
rendItem(ctx2,items,220,56);
</script>
最后综合选了canvas省事点,但是以上这些实现都有一个问题,就是参与排列的图片如果高度不一样,就蛋疼了无法控制按基线对齐分布,全部都是居中的,暂时还没彻底习惯canvas里面的坐标体系,暂时搁置。