Javascript JS 3d图像旋转svg/canvas

Javascript JS 3d图像旋转svg/canvas,javascript,image,svg,canvas,carousel,Javascript,Image,Svg,Canvas,Carousel,我想创建这样的图像旋转木马我尝试了许多解决方案,但看起来不太好…:(我试着用css制作3d变换、svg路径和画布上的绘图,但在每个解决方案中,我的结果都很平淡。 也许这里有人对此有什么想法?也许有人知道一些库/框架?我应该使用css、svg或画布 谢谢大家 例如: 使用时: CSS body { margin: 0; padding: 0; min-width: 900px; } .carousel { display: flex; justify-content:

我想创建这样的图像旋转木马我尝试了许多解决方案,但看起来不太好…:(我试着用css制作3d变换、svg路径和画布上的绘图,但在每个解决方案中,我的结果都很平淡。 也许这里有人对此有什么想法?也许有人知道一些库/框架?我应该使用css、svg或画布

谢谢大家

例如:

使用时:

CSS

body {
  margin: 0;
  padding: 0;
  min-width: 900px;
}

.carousel {
  display: flex;
  justify-content: space-between;
  margin: 0 -33px 0 -14px;
  padding: 0;
}

.carousel svg:nth-child(2) {
  margin-left: -21px;
}
class AdvImagesCarousel{
    constructor(id){
        this.animationFrameTime;
        this.id                     = id;
        this.slides                 = [];
        this.default_slide_width    = 649;
        this.default_slide_height   = 900;
        this.mouse_start_move       = 0;
        this.mouse_is_down          = false;
        this.wrapper;
    }

    addSlide(img_src, title, url){
        var key = this.slides.length;
        this.slides[key] = new AdvImagesCarouselImageSlide(img_src, title, url);
    }

    calcSizeByWindowWidth(size){
        return $(window).width() * (size / 19.20 / 100);
    }
    setLayout(){
        for(var k in this.slides){
            this.slides[k].setLayout( this.calcSizeByWindowWidth(this.default_slide_width), this.calcSizeByWindowWidth(this.default_slide_height) );
        }
    }

    init(){
        var k;
        var that = this;
        this.wrapper = $("#" + this.id);

        for(k in this.slides){
            this.wrapper.append( this.slides[k].getCode(this.id + "_" + k) );
            this.slides[k].init(k);
        }

        this.setLayout();
        $(window).resize(function(){
            that.setLayout();
        });

        $("#" + this.id).mousedown(function(ev){
            that.mouse_is_down = true;
            that.mouse_start_move = ev.clientX;
        });
        $("#" + this.id).mouseup(function(ev){
            that.mouse_is_down = false;
            that.mouse_start_move = 0;
        });
        $("#" + this.id).mousemove(function(ev){
            if(that.mouse_is_down){
                var move = ev.clientX - that.mouse_start_move;
                if(move > 50){
                    that.mouse_is_down = false;
                    that.mouse_start_move = 0;
                    that.moveSlide(1);
                }else if(move < -50){
                    that.mouse_is_down = false;
                    that.mouse_start_move = 0;
                    that.moveSlide(-1);
                }
            }
        });
    }

    moveSlide(move){
        var k, slide;
        for(k in this.slides){
            slide = this.slides[k];
            slide.animeToShape( (slide.current_pos + move) );
        }
    }
}

class AdvImagesCarouselImageSlide{

    constructor(img_src, title, url, parent_id){
        this.parent_id      = parent_id;
        this.img_src        = img_src;
        this.title          = title;
        this.url            = url;
        this.current_pos    = 0;
        this.shapesValues   = [7, 14, 642, 630, 634, 320, 20, 622, 480, 613, 714, 464, 718, 265, 725, 760, 356, 649, 637, 272, 706, 712, 27, 390, 616, 305, 326, 727];
        this.default_shapes = [
            "M 14 0 L 613 0 C 634 320, 622 480, 613 714 C 464 718, 265 725, 14 760 C 14 356, 14 356, 14 0",
            "M 7 0 L 642 0 C 630 356, 630 356, 642 712 C 265 706, 265 706, 7 712 C 20 356, 20 356, 7 0",
            "M 14 0 L 616 0 C 616 390, 616 390, 616 760 C 305 727, 326 727, 14 714 C 0 356, 0 356, 14 0",
        ];
        this.shapes         = [
            "M 14 0 L 613 0 C 634 320, 622 480, 613 714 C 464 718, 265 725, 14 760 C 14 356, 14 356, 14 0",
            "M 7 0 L 642 0 C 630 356, 630 356, 642 712 C 265 706, 265 706, 7 712 C 20 356, 20 356, 7 0",
            "M 14 0 L 616 0 C 616 390, 616 390, 616 760 C 305 727, 326 727, 14 714 C 0 356, 0 356, 14 0",
        ];
        this.key;
        this.slide_id;
        this.image_id;
        this.width;
        this.height;
    }

    getCode(key){
        if(!key){
            key = this.key;
        }
        this.key        = key;
        this.slide_id   = "slide_"+key;
        return '<svg width="1" height="1" id="'+this.slide_id+'">' +
                    '<defs>' +
                        '<pattern class="img" id="img_'+this.slide_id+'" patternUnits="userSpaceOnUse" width="1" height="1" x="0" y="0">' +
                            '<image href="'+this.img_src+'" x="0" y="0" width="100%" height="100%" preserveAspectRatio="xMidYMin slice" />' +
                        '</pattern>' +
                    '</defs> ' +
                    '<path class="shape" fill="url(#img_'+this.slide_id+')" d=""/>' +
                '</svg>';
    }

    calcSizeByWindowWidth(size){
        return Math.round($(window).width() * (size / 19.20 / 100));
    }
    recalculateShapeValues(string){
        var k, val;
        for(k in this.shapesValues){
            val = this.shapesValues[k];
            string = string.replace(new RegExp(' '+val, 'g'), ' '+this.calcSizeByWindowWidth(val));
        }
        return string;
    }
    recalculateShapes(){
        for(var k in this.default_shapes){
            this.shapes[k] = this.recalculateShapeValues(this.default_shapes[k]);
        }
    }
    setLayout(width, height){
        this.width  = width;
        this.height = height;
        $('#' + this.slide_id).attr('width', width);
        $('#' + this.slide_id).attr('height', height);
        $('#' + this.slide_id + ' .img').attr('width', width);
        $('#' + this.slide_id + ' .img').attr('height', height);

        this.recalculateShapes();
        this.setShape(this.current_pos);
    }

    init(position){
        this.setShape(position);
    }

    setShape(position){
        if(this.shapes[position]){
            $('#' + this.slide_id + ' .shape').attr('d', this.shapes[position]);
            this.current_pos = parseInt(position);
        }
    }
    animeToShape(position){
        var that = this;
        if(this.shapes[position]){
            anime({
                targets: '#'+that.slide_id+' .shape',
                d: [
                    { value: that.shapes[position] },
                ],
                easing: 'cubicBezier(.28,1.43,.52,.99)',
                duration: 1500,
                loop: false
            });
        }
        anime({
            targets: '#'+that.slide_id,
            translateX: that.width+20+'px',
            easing: 'cubicBezier(.28,1.43,.52,.99)',
            duration: 1500,
            loop: false
        });
        this.current_pos = parseInt(position);
    }
}

var carousel = new AdvImagesCarousel("carousel");
carousel.addSlide("https://upload.wikimedia.org/wikipedia/commons/9/99/InsSight_spacecraft_appendix_gallery_Image_55-full.jpg", "Title 1", "#url_1");
carousel.addSlide("https://www.w3schools.com/w3css/img_forest.jpg", "Title 2", "#url_2");
carousel.addSlide("https://www.gettyimages.pt/gi-resources/images/Homepage/Hero/PT/PT_hero_42_153645159.jpg", "Title 3", "#url_3");
carousel.init();
JS

body {
  margin: 0;
  padding: 0;
  min-width: 900px;
}

.carousel {
  display: flex;
  justify-content: space-between;
  margin: 0 -33px 0 -14px;
  padding: 0;
}

.carousel svg:nth-child(2) {
  margin-left: -21px;
}
class AdvImagesCarousel{
    constructor(id){
        this.animationFrameTime;
        this.id                     = id;
        this.slides                 = [];
        this.default_slide_width    = 649;
        this.default_slide_height   = 900;
        this.mouse_start_move       = 0;
        this.mouse_is_down          = false;
        this.wrapper;
    }

    addSlide(img_src, title, url){
        var key = this.slides.length;
        this.slides[key] = new AdvImagesCarouselImageSlide(img_src, title, url);
    }

    calcSizeByWindowWidth(size){
        return $(window).width() * (size / 19.20 / 100);
    }
    setLayout(){
        for(var k in this.slides){
            this.slides[k].setLayout( this.calcSizeByWindowWidth(this.default_slide_width), this.calcSizeByWindowWidth(this.default_slide_height) );
        }
    }

    init(){
        var k;
        var that = this;
        this.wrapper = $("#" + this.id);

        for(k in this.slides){
            this.wrapper.append( this.slides[k].getCode(this.id + "_" + k) );
            this.slides[k].init(k);
        }

        this.setLayout();
        $(window).resize(function(){
            that.setLayout();
        });

        $("#" + this.id).mousedown(function(ev){
            that.mouse_is_down = true;
            that.mouse_start_move = ev.clientX;
        });
        $("#" + this.id).mouseup(function(ev){
            that.mouse_is_down = false;
            that.mouse_start_move = 0;
        });
        $("#" + this.id).mousemove(function(ev){
            if(that.mouse_is_down){
                var move = ev.clientX - that.mouse_start_move;
                if(move > 50){
                    that.mouse_is_down = false;
                    that.mouse_start_move = 0;
                    that.moveSlide(1);
                }else if(move < -50){
                    that.mouse_is_down = false;
                    that.mouse_start_move = 0;
                    that.moveSlide(-1);
                }
            }
        });
    }

    moveSlide(move){
        var k, slide;
        for(k in this.slides){
            slide = this.slides[k];
            slide.animeToShape( (slide.current_pos + move) );
        }
    }
}

class AdvImagesCarouselImageSlide{

    constructor(img_src, title, url, parent_id){
        this.parent_id      = parent_id;
        this.img_src        = img_src;
        this.title          = title;
        this.url            = url;
        this.current_pos    = 0;
        this.shapesValues   = [7, 14, 642, 630, 634, 320, 20, 622, 480, 613, 714, 464, 718, 265, 725, 760, 356, 649, 637, 272, 706, 712, 27, 390, 616, 305, 326, 727];
        this.default_shapes = [
            "M 14 0 L 613 0 C 634 320, 622 480, 613 714 C 464 718, 265 725, 14 760 C 14 356, 14 356, 14 0",
            "M 7 0 L 642 0 C 630 356, 630 356, 642 712 C 265 706, 265 706, 7 712 C 20 356, 20 356, 7 0",
            "M 14 0 L 616 0 C 616 390, 616 390, 616 760 C 305 727, 326 727, 14 714 C 0 356, 0 356, 14 0",
        ];
        this.shapes         = [
            "M 14 0 L 613 0 C 634 320, 622 480, 613 714 C 464 718, 265 725, 14 760 C 14 356, 14 356, 14 0",
            "M 7 0 L 642 0 C 630 356, 630 356, 642 712 C 265 706, 265 706, 7 712 C 20 356, 20 356, 7 0",
            "M 14 0 L 616 0 C 616 390, 616 390, 616 760 C 305 727, 326 727, 14 714 C 0 356, 0 356, 14 0",
        ];
        this.key;
        this.slide_id;
        this.image_id;
        this.width;
        this.height;
    }

    getCode(key){
        if(!key){
            key = this.key;
        }
        this.key        = key;
        this.slide_id   = "slide_"+key;
        return '<svg width="1" height="1" id="'+this.slide_id+'">' +
                    '<defs>' +
                        '<pattern class="img" id="img_'+this.slide_id+'" patternUnits="userSpaceOnUse" width="1" height="1" x="0" y="0">' +
                            '<image href="'+this.img_src+'" x="0" y="0" width="100%" height="100%" preserveAspectRatio="xMidYMin slice" />' +
                        '</pattern>' +
                    '</defs> ' +
                    '<path class="shape" fill="url(#img_'+this.slide_id+')" d=""/>' +
                '</svg>';
    }

    calcSizeByWindowWidth(size){
        return Math.round($(window).width() * (size / 19.20 / 100));
    }
    recalculateShapeValues(string){
        var k, val;
        for(k in this.shapesValues){
            val = this.shapesValues[k];
            string = string.replace(new RegExp(' '+val, 'g'), ' '+this.calcSizeByWindowWidth(val));
        }
        return string;
    }
    recalculateShapes(){
        for(var k in this.default_shapes){
            this.shapes[k] = this.recalculateShapeValues(this.default_shapes[k]);
        }
    }
    setLayout(width, height){
        this.width  = width;
        this.height = height;
        $('#' + this.slide_id).attr('width', width);
        $('#' + this.slide_id).attr('height', height);
        $('#' + this.slide_id + ' .img').attr('width', width);
        $('#' + this.slide_id + ' .img').attr('height', height);

        this.recalculateShapes();
        this.setShape(this.current_pos);
    }

    init(position){
        this.setShape(position);
    }

    setShape(position){
        if(this.shapes[position]){
            $('#' + this.slide_id + ' .shape').attr('d', this.shapes[position]);
            this.current_pos = parseInt(position);
        }
    }
    animeToShape(position){
        var that = this;
        if(this.shapes[position]){
            anime({
                targets: '#'+that.slide_id+' .shape',
                d: [
                    { value: that.shapes[position] },
                ],
                easing: 'cubicBezier(.28,1.43,.52,.99)',
                duration: 1500,
                loop: false
            });
        }
        anime({
            targets: '#'+that.slide_id,
            translateX: that.width+20+'px',
            easing: 'cubicBezier(.28,1.43,.52,.99)',
            duration: 1500,
            loop: false
        });
        this.current_pos = parseInt(position);
    }
}

var carousel = new AdvImagesCarousel("carousel");
carousel.addSlide("https://upload.wikimedia.org/wikipedia/commons/9/99/InsSight_spacecraft_appendix_gallery_Image_55-full.jpg", "Title 1", "#url_1");
carousel.addSlide("https://www.w3schools.com/w3css/img_forest.jpg", "Title 2", "#url_2");
carousel.addSlide("https://www.gettyimages.pt/gi-resources/images/Homepage/Hero/PT/PT_hero_42_153645159.jpg", "Title 3", "#url_3");
carousel.init();
class AdvImagesCarousel{
建造师(id){
这是animationFrameTime;
this.id=id;
this.slides=[];
this.default\u slide\u width=649;
this.default\u slide\u height=900;
this.mouse\u start\u move=0;
this.mouse\u is\u down=false;
这是包装纸;
}
添加幻灯片(img_src、标题、url){
var key=this.slides.length;
this.slides[key]=新的AdvImagesCarouselImageSlide(img_src,title,url);
}
calcSizeByWindowWidth(尺寸){
返回$(window).width()*(size/19.20/100);
}
setLayout(){
for(本幻灯片中的变量k){
this.slides[k].setLayout(this.calcsizebyindowwidth(this.default\u slide\u width),this.calcsizebyindowwidth(this.default\u slide\u height));
}
}
init(){
var-k;
var=这个;
this.wrapper=$(“#”+this.id);
for(本幻灯片中的k){
this.wrapper.append(this.slides[k].getCode(this.id+“”+k));
this.slides[k].init(k);
}
这个.setLayout();
$(窗口)。调整大小(函数(){
setLayout();
});
$(“#”+this.id).mousedown(函数(ev){
that.mouse\u is\u down=true;
that.mouse\u start\u move=ev.clientX;
});
$(“#”+this.id).mouseup(函数(ev){
that.mouse\u is\u down=false;
鼠标开始移动=0;
});
$(“#”+this.id).mousemove(函数(ev){
如果(鼠标按下){
var move=ev.clientX-that.mouse\u start\u move;
如果(移动>50){
that.mouse\u is\u down=false;
鼠标开始移动=0;
那.移动幻灯片(1);
}否则,如果(移动<-50){
that.mouse\u is\u down=false;
鼠标开始移动=0;
即:移动幻灯片(-1);
}
}
});
}
移动幻灯片(移动){
var k,幻灯片;
for(本幻灯片中的k){
slide=this.slides[k];
slide.animeToShape((slide.current_pos+move));
}
}
}
类AdvImagesCarouselImageSlide{
构造函数(img\u src、标题、url、父id){
this.parent\u id=parent\u id;
this.img_src=img_src;
this.title=标题;
this.url=url;
这是当前位置=0;
this.shapesValues=[7,14,642,630,634,320,20,622,480,613,714,464,718,265,725,760,356,649,637,272,706,712,27,390,616,305,326,727];
这是默认的形状=[
“M 14 0 L 613 0 C 634 320、622 480、613 714 C 464 718、265 725、14 760 C 14 356、14 356、14 0”,
“M 7 0 L 642 0 C 630 356、630 356、642 712 C 265 706、265 706、7 712 C 20 356、20 356、7 0”,
“M 14 0 L 616 0 C 616 390、616 390、616 760 C 305 727、326 727、14 714 C 0 356、0 356、14 0”,
];
这是一个形状=[
“M 14 0 L 613 0 C 634 320、622 480、613 714 C 464 718、265 725、14 760 C 14 356、14 356、14 0”,
“M 7 0 L 642 0 C 630 356、630 356、642 712 C 265 706、265 706、7 712 C 20 356、20 356、7 0”,
“M 14 0 L 616 0 C 616 390、616 390、616 760 C 305 727、326 727、14 714 C 0 356、0 356、14 0”,
];
这把钥匙;
这个.slide_id;
这个.image\u id;
这是宽度;
这是身高;
}
getCode(键){
如果(!键){
key=this.key;
}
this.key=key;
此.slide\u id=“slide\u”+键;
返回“”+
'' +
'' +
'' +
'' +
' ' +
'' +
'';
}
calcSizeByWindowWidth(尺寸){
返回Math.round($(window.width()*(size/19.20/100));
}
重新计算值(字符串){
var k,val;
for(此.shapesValues中的k){
val=此。形状值[k];
string=string.replace(新的RegExp(“”+val,'g'),“”+this.calcsizebyindowwidth(val));
}
返回字符串;
}
重新计算图表(){
for(此.default_形状中的变量k){
this.shapes[k]=this.recreacteShapeValues(this.default_shapes[k]);
}
}
设置布局(宽度、高度){
这个。宽度=宽度;
高度=高度;
$(“#”+this.slide_id).attr('width',width);
$(“#”+this.slide_id).attr('height',height);
$(“#”+this.slide_id+”.img').attr('width',width);
$(“#”+this.slide_id+”.img').attr('height',height);
这是。重新计算图像();
此.setShape(此.current_pos);
}
初始(位置){
此。设置形状(位置);
}
设置形状(位置){
if(this.shapes[位置]){
$(“#”+this.slide_id+”.shape').attr('d',this.shapes[position]);
this.current_pos=parseInt(位置);
}
}
动物形状(位置){
var=这个;
if(this.shapes[位置]){
动画({
目标:'#'+that.slide_id+'.shape',
d:[
{value:that.shapes[position]},
],
缓和:“cubicBezier(.28,1.43,52,99)”,
持续时间:1500,
循环:false
});
}
动画({
目标:“#”+t