Effect preview
Press the "click preview" button on the right to preview on the current page, and click the link to preview in full screen.
https://codepen.io/comehope/pen/gdVObN
Interactive video
This video is interactive, you can pause the video at any time and edit the code in the video.
Please use chrome, safari, edge to watch.
https://scrimba.com/p/pEgDAM/caRLack
Source code download
Please download the full source code of the daily front-end combat series from github:
https://github.com/comehope/front-end-daily-challenges
Code interpretation
Define dom. The container contains 2 sub-containers, .horizontal
representing horizontal line segments and .vertical
vertical line segments. Each sub-container contains 4 sub-elements:
<div class="container">
<div class="horizontal">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="vertical">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
Center display:
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: skyblue;
}
Size of the container set, where --side-length
is the number of elements of each side of the square:
.container {
--side-length: 2;
position: relative;
width: calc(40px * calc(var(--side-length)));
height: calc(40px * calc(var(--side-length)));
}
Arrange the child elements in a grid layout, and arrange the 4 elements into a 2 * 2 square matrix:
.container .horizontal,
.container .vertical {
position: absolute;
top: 0;
left: 0;
display: grid;
grid-template-columns: repeat(var(--side-length), 1fr);
}
Set the style .horizontal
of the child element , the inner child element is a horizontal bar, and the .vertical
inner child element is a vertical bar:
.container .horizontal span {
width: 40px;
height: 10px;
background: #fff;
margin: 15px 0;
}
.container .vertical span {
width: 10px;
height: 40px;
background: #fff;
margin: 0 15px;
}
At this point, the static layout is complete, and then use d3 to batch process the child elements.
Introduce the d3 library:
<script src="https://d3js.org/d3.v5.min.js"></script>
Delete the dom node of the child element in the html file, and delete the css variable declared in the css file.
Define the number of elements on each side of the square matrix and assign this value to the css variable:
const SIDE_LENGTH = 2;
let container = d3.select('.container')
.style('--side-length', SIDE_LENGTH);
Adding a defined span
function child element, were added to the horizontal and vertical sub-elements:
function appendSpan(selector) {
container.select(selector)
.selectAll('span')
.data(d3.range(SIDE_LENGTH * SIDE_LENGTH))
.enter()
.append('span');
}
appendSpan('.horizontal');
appendSpan('.vertical');
In this case, the layout has been changed to dynamic, you can modify SIDE_LENGTH
to create different side length of the square of value, such as the following statement will create a square 5 * 5:
const SIDE_LENGTH = 5;
Next, use GSAP to create the animation. (Note: because scrimba will crash when using gsap, so the video demonstration uses css animation, but codepen and github both use gsap animation)
Introduce GSAP library:
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
Animation variable declaration animation
, a statement on behalf of dom elements of variable $horizontalSpan
and $verticalSpan
:
let animation = new TimelineMax({repeat: -1});
let $horizontalSpan = '.container .horizontal span';
let $verticalSpan = '.container .vertical span';
Create animated bar, a total of 4 steps, each of to
the last parameter is the name of the statement of the steps of:
animation.to($horizontalSpan, 1, {rotation: 45}, 'step1')
.to($horizontalSpan, 1, {x: '-10px', y: '-10px'}, 'step2')
.to($horizontalSpan, 1, {rotation: 0, x: '0', y: '0', scaleY: 2, scaleX: 0.5}, 'step3')
.to($horizontalSpan, 1, {rotation: 90, scaleY: 1, scaleX: 1}, 'step4')
Then create the animation of the vertical bar, to
the step name of the statement is the same as the step name of the horizontal bar, so as to keep the animation synchronized with the horizontal bar:
animation.to($verticalSpan, 1, {rotation: 45}, 'step1')
.to($verticalSpan, 1, {x: '10px', y: '10px'}, 'step2')
.to($verticalSpan, 1, {x: '0', y: '0', scaleX: 2, scaleY: 0.5}, 'step3')
.to($verticalSpan, 1, {rotation: 90, scaleX: 1, scaleY: 1}, 'step4');
At the end of the animation, use the time scale scaling function to double the animation playback speed:
animation.timeScale(2);
Finally, change the side length of the square to 10, the larger the square, the more powerful it will be:
const SIDE_LENGTH = 10;
You're done!