A lot has been said on the use of traditional 2D carousels, for example this piece on Smashing Magazine covers this subject. There’s no simple yes or no answer to the ‘should I use a carousel?’ question; it depends on the particular situation.
When I started researching this topic, I didn’t need a 3D carousel, but rather, I was more interested in the technical details on implementing it. The core employed techniques are of course from the CSS Transforms Module Level 1, but along the way a bunch of other front end development technologies will be applied, touching on various topics in CSS, Sass, and client-side JavaScript.
This CodePen displays different versions of the component I’ll be showing you how to build.
该CodePen显示组件的不同版本,我将向您展示如何构建 。
To illustrate the setup of the CSS 3D transforms, I’ll show you a CSS-only version of the component. Then, I’ll show you how to enhance it with JavaScript, developing a simple component script.
For the markup, the images inside the component are wrapped inside a element, which provides a basic skeleton:
对于标记,组件内部的图像被包装在元素内,该元素提供了基本的骨架:
...
This will be our starting point.
这将是我们的出发点。
轮播的几何结构 (The Carousel Geometric Structure)
Before looking into the CSS, let’s have an overview of the plan that will be developed in the following sections.
在研究CSS之前,我们先概述一下将在以下各节中制定的计划。
The elements should be arranged around the circle delineated by the carousel. This circle can be approximated by its circumscribed regular polygon and the images placed on its sides:
元素应围绕旋转木马划定的圆圈排列。 该圆可通过其外接的正多边形和放置在其侧面的图像来近似:
So, the number of sides of such a polygon is the same as the number of images in the carousel: with three images, the polygon is an equilateral triangle; with four images it is a square; with five a pentagon; and so on:
See the Pen Regular Polygons by SitePoint (@SitePoint) on CodePen.
见笔正多边形由SitePoint( @SitePoint上) CodePen 。
What if there are fewer than three images in the carousel? The polygon cannot be defined and the following procedure cannot be applied as it is. Anyway, the case of only one image is rather useless; two images are slightly more probable, and they could be placed on two diametrically opposed points on the circle. For simplicity, these special cases aren’t handled and at least three images are assumed. However, the relative code modifications would not be hard.
This imaginary reference polygon will be positioned in 3D space, perpendicular to the plane of the viewport and with its center pushed back into the screen at a distance equal to its apothem, the distance of a side of the polygon from its center, as illustrated in this top down view of the carousel:
This way, the side that is currently facing the viewer will be on the screen plane at z = 0, and the front image, not being affected by the perspective foreshortening, will have its ordinary 2D size. The d letter in the picture represents the value for the CSS perspective property.
In this section I’ll show you the key CSS rules, which I’ll go through step by step.
在本节中,我将向您展示关键CSS规则,并将逐步进行介绍。
In the following code snippets, some Sass variables are used to make the component more configurable. I’ll use $n to denote the number of images in the carousel and $item-width to specify the width of an image.
The element is the containing box for the first image and the reference element around which the other images are positioned and transformed. Supposing, just for now, that the carousel had only one image to showcase, I can start with the sizing and the alignment:
The element has the prescribed carousel item width and it has the same height of the images (they can have different sizes but they must have the same aspect ratio). In this way, the carousel container height adapts itself based on the height of the images. Also, is horizontally centered in the carousel container.
The first image doesn’t need additional transformations because it is already in its target position, i.e., on the front face of the carousel.
第一个图像不需要进行其他转换,因为它已经处于其目标位置,即在转盘的前面。
The carousel can be turned in 3D space by applying a rotation transform to the element. This rotation has to be around the center of the polygon, so I’ll change the default transform origin of :
This value is negated because in CSS the positive direction of the z-axis is off the screen, toward the viewer. The parentheses are needed to avoid Sass syntax errors. The computation of the polygon apothem will be explained later.
The z-index values are ignored because this is only a preliminary step for the following transformations. In fact, now each image can be rotated on the y-axis of the carousel by a rotation angle that depends on the polygon side on which the image is assigned. First, as done with the element, the default transform origin of the images is modified, moving it to the center of the polygon:
Then the images can be rotated on their new y-axis by an amount given by ($i - 1) * $theta radians, where $i is the index (starting from one) of the image and $theta = 2 * $PI / $n, with $PI representing the mathematical constant pi. Therefore, the second image will be rotated by $theta, the third by 2 * $theta, and so on, up to the last image that will be rotated by ($n - 1) * $theta.
This relative arrangement of the images will be preserved during the rotations of the carousel (that is, the rotation about the modified y-axis of ) thanks to the hierarchical nature of the nested CSS transforms.
由于嵌套CSS转换的层次性质,在轮播旋转期间(即绕的修改后的y轴旋转),将保留图像的这种相对排列。
This per-image rotation amount can be assigned using the Sass @for control directive:
This is using the for...through construct rather than for...to because with for...to the last value assigned to the index variable $i would be n-1 instead of n.
Note the two instances of Sass’s #{} interpolation syntax. In the first instance it’s used for the index of the :nth-child() selector; in the second instance it’s used to set the rotation property value.
The computation of the polygon’s apothem depends on the number of sides and the width of a side, that is, on the $n and $item-width variables. The formula is:
多边形的矩的计算取决于边的数量和边的宽度,即$n和$item-width变量。 公式为:
$image-width / (2 * tan($PI/$n))
where tan() is the tangent trigonometric function.
其中tan()是正切三角函数 。
This formula can be derived with a bit of geometry and trigonometry. In the pen source, this formula is not implemented as written because the tangent function is not readily available in Sass, so a hardcoded value is used instead. The formula will be fully implemented in the JavaScript demo instead.
At this point the carousel images are “sewn” side by side, forming the required polygonal shape. But here they are tightly packed, while often in 3D carousels there is space between them. This distance enhances the perception of a 3D space because it allows you to see the back-facing images on the rear of the carousel.
It is possible to optionally add this gap between the images by introducing another configuration variable, $item-separation, and using it as the horizontal padding for each element. More precisely, taking half of this value for the left and right padding:
The images are made translucent with the opacity property to better illustrate the carousel structure, and the flex layout on the carousel root element was used to vertically center it in the viewport.
To facilitate testing of the carousel rotation, I’m going to add a UI control to navigate back and forth between the images. See the CodePen demo for the HTML, CSS and JavaScript implementing this control; here I’ll describe only the code relating to the rotation.
We use a currImage integer variable to indicate which image is at the front of the carousel. When the user interacts with the previous/next buttons, this variable is incremented or decremented by one unit.
(Here and in the following snippets, ES6 template literals are employed to interpolate expressions in strings; feel free to use the traditional ‘+’ concatenation operator if you prefer)
The rotation is by - theta because to navigate to the next item a counter-clockwise rotation is needed and such rotation values are negative in CSS transforms.
旋转角度为- theta因为要导航到下一个项目,需要逆时针旋转,并且这种旋转值在CSS变换中为负。
Note that the currImage value is not constrained to the [0, numImages – 1] range, but instead it can grow indefinitely, both in the positive and in the negative direction. In fact, If the image on the front is the last one (so currImage == n-1), and the user clicks the next button, if we reset currImage to 0 to advance to the first carousel image, there would be a transition of the rotation angle from (n-1)*theta to 0 and this would turn the carousel in the opposite direction across all the previous images. A similar issue would happen when clicking the prev button when the front image is the first one.
To be picky, I should even check for potential overflows of currentImage, because the Number data type cannot take arbitrarily large values. These checks are not implemented in the demo code.
Having seen the basic CSS that lies at the core of the carousel, now JavaScript can be used to enhance the component in several ways, such as:
看到了旋转木马核心的基本CSS之后,现在可以使用JavaScript通过多种方式增强组件,例如:
Arbitrary number of images 任意数量的图像
Images with percentage widths 具有百分比宽度的图像
Multiple carousel instances on the page 页面上有多个轮播实例
Per-instance configurations, such as the gap size and the back-face visibility 每个实例的配置,例如间隙大小和背面可见性
Configuration using HTML5 data-* attributes 使用HTML5 data- *属性进行配置
First I remove from the style sheet the variables and rules related to the transform origins and the rotations, because these will be done using JavaScript:
首先,我从样式表中删除与转换原点和旋转相关的变量和规则,因为这些将使用JavaScript完成:
$item-width: 40%; // Now we can use percentages
$item-separation: 0px; // This now is set with Js
$viewer-distance: 500px;
.carousel {
padding: 20px;
perspective: $viewer-distance;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
> * {
flex: 0 0 auto;
}
figure {
margin: 0;
width: $item-width;
transform-style: preserve-3d;
transition: transform 0.5s;
img {
width: 100%;
box-sizing: border-box;
padding: 0 $item-separation / 2;
&:not(:first-of-type) {
position: absolute;
left: 0;
top: 0;
}
}
}
}
Next in the script is a carousel() function that takes care of the initialization of an instance:
脚本中的下一个是carousel()函数,它负责实例的初始化:
function carousel(root) {
// coming soon...
}
The root argument refers to the DOM element that holds the carousel.
root参数是指持有轮播的DOM元素。
Usually this function would be a constructor, to generate one object for each carousel on the page, but here I am not writing a carousel library, so a simple function will be sufficient.
To instantiate several components on the same page, the code waits that all the images are loaded, registering a listener on the window object for the load event, and then invokes carousel() for each element with the carousel class:
window.addEventListener('load', () => {
var carousels = document.querySelectorAll('.carousel');
for (var i = 0; i < carousels.length; i++) {
carousel(carousels[i]);
}
});
carousel() executes three main tasks:
carousel()执行三个主要任务:
The navigation setup. This is the same code presented in the second CodePen demo 导航设置。 这与第二个CodePen演示中呈现的代码相同
The transforms setup 转换设置
Register a window resize listener to keep the carousel responsive, adapting it to the new viewport size 注册一个窗口调整大小的侦听器,以保持轮播响应,使其适应新的视口大小
Before examining the transform setup code, I’ll go through some key variables and how they are initialized based on the instance configuration:
在检查转换设置代码之前,我将介绍一些关键变量以及如何根据实例配置对其进行初始化:
var
figure = root.querySelector('figure'),
images = figure.children,
n = images.length,
gap = root.dataset.gap || 0,
bfc = 'bfc' in root.dataset
;
The number of images (n), is initialized based on the number of child elements of the element. The separation between the slides (gap), is initialized from the HTML5 data-gap attribute, if set. The backside visibility flag (bfc), is read using HTML5’s dataset API. This will be used later to determine if the images on the back of the carousel should be visible or not.
根据元素的子元素数量初始化图像数量( n )。 幻灯片之间的gap ( gap )是从HTML5 data-gap属性(如果已设置)初始化的。 使用HTML5的数据集API读取背面可见性标志( bfc )。 稍后将使用它来确定转盘背面的图像是否应可见。
设置CSS转换 (Setting the CSS Transforms)
The code that sets the CSS transforms-related properties is encapsulated in setupCarousel(). This nested function takes two arguments. The first is the number of items in the carousel, that is, the n variable introduced above. The second parameter, s, is the length of the side of the carousel polygon. As I mentioned earlier, this is equal to the width of the images, so it is possible to read the current width of one of them with getComputedStyle():
In this way, image widths can be set with percentages values.
这样,可以使用百分比值设置图像宽度。
To keep the carousel responsive, I register a listener for the window resize event that calls setupCarousel() again with the (eventually)modified size of the images:
for (var i = 0; i < n; i++) {
images[i].style.padding = `${gap}px`;
}
for (i = 1; i < n; i++) {
images[i].style.transformOrigin = `50% 50% ${- apothem}px`;
images[i].style.transform = `rotateY(${i * theta}rad)`;
}
if (bfc) {
for (i = 0; i < n; i++) {
images[i].style.backfaceVisibility = 'hidden';
}
}
The first cycle assigns the padding for the space between the carousel items. The second cycle sets the 3D transforms. The last cycle handles the back-faces if the related flag was specified in the carousel configuration.
Finally, rotateCarousel() is called to take the current image to the front. This is a little helper function that, given the index of the image to show, rotates the figure element on its y-axis to move the target image to the front. It is also used by the navigation code to go back and forth:
1,java读取.properties配置文件
InputStream in;
try {
in = test.class.getClassLoader().getResourceAsStream("config/ipnetOracle.properties");//配置文件的路径
Properties p = new Properties()
create or replace procedure proc_test01
as
type emp_row is record(
empno emp.empno%type,
ename emp.ename%type,
job emp.job%type,
mgr emp.mgr%type,
hiberdate emp.hiredate%type,
sal emp.sal%t
今天在执行一个脚本时,本来是想在脚本中启动hdfs和hive等程序,可以在执行到service hive-server start等启动服务的命令时会报错,最终解决方法记录一下:
脚本报错如下:
./olap_quick_intall.sh: line 57: service: command not found
./olap_quick_intall.sh: line 59
最近重新安装的电脑,配置了新环境,老是出现:
adb server is out of date. killing...
ADB server didn't ACK
* failed to start daemon *
百度了一下,说是端口被占用,我开个eclipse,然后打开cmd,就提示这个,很烦人。
一个比较彻底的解决办法就是修改
import java.util.HashMap;
public class Title {
public static void main(String[] args){
f();
}
// 二位数组的应用
//12、二维数组中,哪一行或哪一列的连续存放的0的个数最多,是几个0。注意,是“连续”。
public static void f(){