道路千万条,安全第一条!

魔方结构解析

从魔方的外观来看,可以有多种方式来表达它的组成,从而也有多种方式来形成一个魔方。如:

  • 由六个面组成
  • 由若干层组成
  • 由多个方块组成

无论哪种方式,都可以制作魔方。只是,不同的方式对后续的其它操作会有影响,有些方式甚至会导致利用已有的特性无法直接表达。因此,在这项选择上小纠结一下,理出最易于理解和实施(往往也容易自以为是)的方案是有益的。

这里我们选择“由多个方块组成”的方式来形成魔方。

于是得到魔方的基本结构为:一个魔方由多个魔方格(cube)组成,一个魔方格由多个版面(block)组成。

一些基本要素的表示

六个方向表示:上(up)、下(down)、左(left)、右(right)、前(front)、后(back)

六种颜色表示:黄色(yellow)、白色(white)、橙色(orange)、红色(red)、蓝色(blue)、绿色(green)

初始的魔方组成形式为:上黄,下白,左橙,右红,前蓝,后绿。

绘制魔方格

一个魔方格也有六个方向,每个方向一个版面。在魔方中,一个魔方格可见的只有 1 至 3 个版面。

为了处理方便,每一个魔方格我们总是从前面来看它,从而上、下、左、右、前、后对于每一个魔方格而言都是确定的位置。

版面的绘制

首先,定义版面(block)的基础样式:

.block {
position: absolute;
margin: 0 auto;
border:solid 2px black;
border-radius:3px;
/* 宽高包含边框 */
box-sizing:border-box;
/* 旋转原点 */
transform-origin:0 0 0;
}

一个版面,默认总是“前面”,我们通过旋转将其旋转到指定的方向,每个方向确定的规则如下:

上:为绕 x 轴逆向 90 度,即 rotateX(-90deg)

下:y 轴的 top属性增加一格后绕 x 轴逆向 90 度

左:绕 y 轴 90 度,即 rotateY(90deg)

右:x 轴的 left 属性增加一格后绕 y 轴 90 度

前:本尊不用动

后:z 轴向后平移一格即可,即 translateZ(size px)

为此,我们通过 javascript 定义一个 Block 类,接收方向、颜色与一格大小作为参数,实现动态绘制版面。

<script>
/** 版面 block 类
* direct 方向
* color 颜色
* size 边长大小
**/
function Block(direct, color, size){
this.direct = direct;
this.color = color;
this.size = size;
// 绘制过的 UI 元素对象
this.Element = null; // 在父容器中绘制
this.DrawIn = function(cubeElement){
var e = this.Element || document.createElement('div');
e.style.width = this.size + "px";
e.style.height = this.size + "px"; var top = (this.direct == 'down' ? this.size : 0);
var left = (this.direct == 'right' ? this.size : 0); e.style.top = top + "px";
e.style.left = left + "px";
e.style.backgroundColor = this.color; var rx = (this.direct == 'up' || this.direct == 'down' ? -90 : 0);
var ry = (this.direct == 'left' || this.direct == 'right' ? 90 : 0);;
var tz = (this.direct == 'back' ? this.size : 0); e.style["transform"] = "rotateX(" + rx + "deg) rotateY(" + ry + "deg) translateZ(-" + tz + "px)";
e.className = "block";
this.Element = e;
cubeElement.appendChild(e);
};
} function onload(){
var blockLeft = new Block('left', 'red', 50);
var blockTop = new Block('up', 'yellow', 50);
var blockRight = new Block('right', 'green', 50); blockLeft.DrawIn( document.querySelector(".wrap") );
blockTop.DrawIn( document.querySelector(".wrap") );
blockRight.DrawIn( document.querySelector(".wrap") );
}
</script>

效果如下:

魔方格的绘制

有了版面的绘制,魔方格可以看到是版面的一个集合,我们根据需要组合版面即可。

首先,我们定义一个魔方格的基础样式 cube:

.cube {
position: absolute;
/* 子元素版面是需要三维空间的 */
transform-style: preserve-3d;
}

为了动态绘制魔方格,我们定义一个魔方格的 Cube 类,指定大小,以及指明所需要各版面的方向及颜色即可。为了能将魔方格排列成魔方,可以为魔方格设置一个其位于魔方这个三维体的坐标位置,默认坐标总是(0,0,0)。而魔方的三维坐标我们定义如下:

自左向右为 x 坐标,以三阶为例可取值:0,1,2

自上向下为 y 从标,以三阶为例可取值:0,1,2

自前向后为 z 坐标,以三阶为例可取值:0,1,2

/** 魔方格 Cube 类
* blockSize 为魔方格的边长代表大小
* directColorArray 为指定方向与颜色的数组
* 形式为 [direct,color,direct,color,...]
* x,y,z 为在魔方中的坐标,未指定时默认为0,0,0
**/
function Cube(blockSize, directColorArray, x, y, z){
this.x = x | 0;
this.y = y | 0;
this.z = z | 0;
this.blockSize = blockSize;
this.blocks = [];
/* 根据参数建立 Block 对象 */
for(var i=0; i < directColorArray.length / 2; i++){
this.blocks.push(new Block(directColorArray[ i*2 ], directColorArray[ i*2 + 1 ], this.blockSize));
} // 绘制过的 UI 元素对象
this.Element = null; // 在父容器中绘制
this.DrawIn = function(boxElement, x, y, z){
this.x = this.x | x;
this.y = this.y | y;
this.z = this.z | z;
var e = this.Element || document.createElement('div');
e.style.width = this.blockSize + "px";
e.style.height = this.blockSize + "px";
e.style["transform"] = "translate3d(" + (x * this.blockSize) + "px," + (y * this.blockSize) + "px,-" + (z * this.blockSize) + "px) ";
e.className = "cube"; for(var i=0; i < this.blocks.length; i++) {
this.blocks[i].DrawIn(e);
} this.Element = e; boxElement.appendChild(e);
};
}

以下代码,绘制两个魔方格:

function onload(){
var cube1 = new Cube(50, ['left', 'red', 'up', 'yellow', 'back', 'green']);
var cube2 = new Cube(50, ['right', 'red', 'up', 'yellow', 'back', 'green']); cube1.DrawIn( document.querySelector(".wrap") );
cube2.DrawIn( document.querySelector(".wrap"), 2, 0, 0 );
}

效果如下:

形成魔方

同样,为了包裹起整个魔方,我们定义一个魔方的基础样式,magicBox:

.magicBox {
position: absolute;
transform-style: preserve-3d;
}

接下来,再定义一个 MagicBox 的类,根据魔方初始的摆放格局“上黄,下白,左橙,右红,前蓝,后绿”,我们可以根据指定的维度自动生成其所需要的魔方格,所有的魔方格,均通过平移的方式放置到所属的坐标。

/** 魔方 MagicBox 类
* dimension 阶数
* blockSize 每小格大小
**/
function MagicBox(dimension, blockSize){
this.dimension = dimension;
this.blockSize = blockSize;
this.cubes = []; this.MakeDefaultCubes = function(){
this.cubes = [];
for(var x=0; x < this.dimension; x++){
for(var y=0; y < this.dimension; y++){
for(var z=0; z < this.dimension; z++){
var cube = this.MakeDefaultCube(x, y, z);
if(cube){
this.cubes.push(cube);
}
}
}
}
}; /* 根据魔方格在阶数中的位置生成魔方格,魔方内部的格子忽略 */
this.MakeDefaultCube = function(x, y, z){
var max = this.dimension - 1;
var dc = [];
if(x == 0) dc.push("left", "orange"); else if(x == max) dc.push("right", "red");
if(y == 0) dc.push("up", "yellow"); else if(y == max) dc.push("down", "white");
if(z == 0) dc.push("front", "blue"); else if(z == max) dc.push("back", "green");
if(dc.length == 0) return null;
var cube = new Cube(this.blockSize, dc, x, y, z);
return cube;
} // 构造时自动产生初始魔方格
this.MakeDefaultCubes();
// 绘制过的 UI 元素对象
this.Element = null;
// 在父容器中绘制
this.DrawIn = function(domElement){
var e = this.Element || document.createElement('div');
e.style.width = (this.dimension * this.blockSize) + "px";
e.style.height = (this.dimension * this.blockSize) + "px";
e.className = "magicBox"; for(var i=0; i < this.cubes.length; i++) {
this.cubes[i].DrawIn(e);
}
this.Element = e;
domElement.appendChild(e);
};
}

通过以下代码绘制一个三阶魔方:

var magicBox = new MagicBox(3, 50);
magicBox.DrawIn( document.querySelector(".wrap") );

效果如下:

附本文完整 HTML 页面

以下为本文完整的代码文档,复制到记事本中,保存为.html即可在谷歌浏览器中运行。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSS3 魔方</title>
<!-- 样式部分全写这里 -->
<style>
.wrap {
transform-style: preserve-3d;
width: 300px; height: 300px;
position: relative; /* 定位起点元素 */
border-top:solid 1px gray; /* x 轴 */
border-left:solid 1px gray; /* y 轴 */
/* 倾斜一点方能见立体效果 */
transform: rotateX(-30deg) rotateY(-30deg);
} /* z 轴正方向 */
.zaxis_p {
position:absolute;
width : 300px;
height:1px;
border-top:solid 1px gray;
/* xy面上,90度立起来就是 z */
transform: rotateY(-90deg);
/* 立起来的旋转点 */
transform-origin:0 0 0;
} /* z 轴负方向 */
.zaxis_n {
position:absolute;
width : 300px;
height:1px;
border-top:dashed 1px gray; /*(虚线)*/
transform: rotateY(90deg);
transform-origin:0 0 0;
} .block {
position: absolute;
margin: 0 auto;
border:solid 2px black;
border-radius:3px;
/* 宽高包含边框 */
box-sizing:border-box;
transform-origin:0 0 0;
} .cube {
position: absolute;
/* 子元素版面是需要三维空间的 */
transform-style: preserve-3d;
} .magicBox {
position: absolute;
transform-style: preserve-3d;
} </style> <script>
/** 版面 block 类
* direct 方向
* color 颜色
* size 边长大小
**/
function Block(direct, color, size){
this.direct = direct;
this.color = color;
this.size = size;
// 绘制过的 UI 元素对象
this.Element = null; // 在父容器中绘制
this.DrawIn = function(cubeElement){
var e = this.Element || document.createElement('div');
e.style.width = this.size + "px";
e.style.height = this.size + "px"; var top = (this.direct == 'down' ? this.size : 0);
var left = (this.direct == 'right' ? this.size : 0); e.style.top = top + "px";
e.style.left = left + "px";
e.style.backgroundColor = this.color; var rx = (this.direct == 'up' || this.direct == 'down' ? -90 : 0);
var ry = (this.direct == 'left' || this.direct == 'right' ? 90 : 0);;
var tz = (this.direct == 'back' ? this.size : 0); e.style["transform"] = "rotateX(" + rx + "deg) rotateY(" + ry + "deg) translateZ(-" + tz + "px)";
e.className = "block";
this.Element = e;
cubeElement.appendChild(e);
};
} /** 魔方格 Cube 类
* blockSize 为魔方格的边长代表大小
* directColorArray 为指定方向与颜色的数组
* 形式为 [direct,color,direct,color,...]
* x,y,z 为在魔方中的坐标,未指定时默认为0,0,0
**/
function Cube(blockSize, directColorArray, x, y, z){
this.x = x | 0;
this.y = y | 0;
this.z = z | 0;
this.blockSize = blockSize;
this.blocks = [];
/* 根据参数建立 Block 对象 */
for(var i=0; i < directColorArray.length / 2; i++){
this.blocks.push(new Block(directColorArray[ i*2 ], directColorArray[ i*2 + 1 ], this.blockSize));
} // 绘制过的 UI 元素对象
this.Element = null; // 在父容器中绘制
this.DrawIn = function(boxElement, x, y, z){
this.x = x | this.x;
this.y = y | this.y;
this.z = z | this.z;
var e = this.Element || document.createElement('div');
e.style.width = this.blockSize + "px";
e.style.height = this.blockSize + "px";
e.style["transform"] = "translate3d(" + (this.x * this.blockSize) + "px," + (this.y * this.blockSize) + "px,-" + (this.z * this.blockSize) + "px) ";
e.className = "cube"; for(var i=0; i < this.blocks.length; i++) {
this.blocks[i].DrawIn(e);
} this.Element = e; boxElement.appendChild(e);
};
} /** 魔方 MagicBox 类
* dimension 阶数
* blockSize 每小格大小
**/
function MagicBox(dimension, blockSize){
this.dimension = dimension;
this.blockSize = blockSize;
this.cubes = []; this.MakeDefaultCubes = function(){
this.cubes = [];
for(var x=0; x < this.dimension; x++){
for(var y=0; y < this.dimension; y++){
for(var z=0; z < this.dimension; z++){
var cube = this.MakeDefaultCube(x, y, z);
if(cube){
this.cubes.push(cube);
}
}
}
}
}; /* 根据魔方格在阶数中的位置生成魔方格,魔方内部的格子忽略 */
this.MakeDefaultCube = function(x, y, z){
var max = this.dimension - 1;
var dc = [];
if(x == 0) dc.push("left", "orange"); else if(x == max) dc.push("right", "red");
if(y == 0) dc.push("up", "yellow"); else if(y == max) dc.push("down", "white");
if(z == 0) dc.push("front", "blue"); else if(z == max) dc.push("back", "green");
if(dc.length == 0) return null;
var cube = new Cube(this.blockSize, dc, x, y, z);
return cube;
} // 构造时自动产生初始魔方格
this.MakeDefaultCubes();
// 绘制过的 UI 元素对象
this.Element = null;
// 在父容器中绘制
this.DrawIn = function(domElement){
var e = this.Element || document.createElement('div');
e.style.width = (this.dimension * this.blockSize) + "px";
e.style.height = (this.dimension * this.blockSize) + "px";
e.className = "magicBox"; for(var i=0; i < this.cubes.length; i++) {
this.cubes[i].DrawIn(e);
}
this.Element = e;
domElement.appendChild(e);
};
} function onload(){
/* 版面绘制示例
var blockLeft = new Block('left', 'red', 50);
var blockTop = new Block('up', 'yellow', 50);
var blockRight = new Block('right', 'green', 50); blockLeft.DrawIn( document.querySelector(".wrap") );
blockTop.DrawIn( document.querySelector(".wrap") );
blockRight.DrawIn( document.querySelector(".wrap") );
*/ /* 魔方格绘制示例
var cube1 = new Cube(50, ['left', 'red', 'up', 'yellow', 'back', 'green']);
var cube2 = new Cube(50, ['right', 'red', 'up', 'yellow', 'back', 'green']); cube1.DrawIn( document.querySelector(".wrap") );
cube2.DrawIn( document.querySelector(".wrap"), 2, 0, 0 );
*/ //* 魔方绘制示例
var magicBox = new MagicBox(3, 50);
magicBox.DrawIn( document.querySelector(".wrap") );
//*/
}
</script>
</head> <body style="padding:300px;" onload="onload()">
<div class="wrap">
<div class="zaxis_p"></div>
<div class="zaxis_n"></div>
</div>
</body> </html>

关注微信公众号“时间维度”,让我们走过一段时空交织的时光。

CSS3 制作魔方 - 形成魔方的更多相关文章

  1. CSS3 制作魔方 - 玩转魔方

    在上一篇<CSS3 制作魔方 - 形成魔方>中介绍了一个完整魔方的绘制实现,本文将介绍魔方的玩转,支持上下左右每一层独立地旋转.先来一睹玩转的风采. 1.一个问题 由于魔方格的位置与转动的 ...

  2. css3可拖动的魔方3d

    css3可拖动的魔方3d 主要用到知识点: css3 3d转换 原生js鼠标拖动事件 display:grid 布局 实现的功能 3d魔方 可点击,可拖动 直接看效果 html: <div cl ...

  3. 图解CSS3制作圆环形进度条的实例教程

    圆环形进度条制作的基本思想还是画出基本的弧线图形,然后CSS3中我们可以控制其旋转来串联基本图形,制造出部分消失的效果,下面就来带大家学习图解CSS3制作圆环形进度条的实例教程 首先,当有人说你能不能 ...

  4. css3制作旋转动画

    现在的css3真是强大,之前很多动画都是用jq来实现,但是css3制作的动画要比jq实现起来简单很多,今天呢,我自己也写了一个css旋转动画和大家分享.效果如下面的图片 思路:1.制作之前呢,我们先来 ...

  5. 详解用CSS3制作圆形滚动进度条动画效果

    主  题 今天手把手教大家用CSS3制作圆形滚动进度条动画,想不会都难!那么,到底是什么东东呢?先不急,之前我分享了一个css实现进度条效果的博客<CSS实现进度条和订单进度条>,但是呢, ...

  6. CSS3制作心形头像

    1.功能需求: 最近有一个基于微信开发的Mobile Web项目,是一个活动页面.功能需求:用户使用微信扫描二维码,然后授权使用微信登录,然后读取用户的昵称和头像,然后显示在一个饼图上面.头像需要有一 ...

  7. 使用 jQuery 和 CSS3 制作滑动导航菜单

    这个下拉菜单可以让你的网站非常优雅,滑动框导航效果令人印象深刻.此外,子菜单框也可以与此集成起来以使其更具吸引力.导航是网站成功的关键之一,有吸引力的导航能够引导用户浏览网站中的更多内容. 效果演示  ...

  8. 使用 jQuery & CSS3 制作美丽的照片画廊

    在本教程中,我们将创建一个很好看的照片画廊效果.我们的想法是,以显示专辑作为一个滑块,而当这张专辑被选中,我们将使用一个美丽的照片堆栈展示专辑的图像.在照片堆栈视图,我们可以通过将最上面的图像移动到所 ...

  9. 网页特效:用CSS3制作3D图片立方体旋转特效

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  10. BonBon - 使用 CSS3 制作甜美的糖果按钮

    BonBon 是一组使用 CSS3 制作的甜美的糖果按钮样式.在过去,我们都是使用图片或者 JavaScript 来实现漂亮的按钮效果,随着越来越多的浏览器对 CSS3 的支持和完善,使用 CSS3 ...

随机推荐

  1. 深入Garbage First垃圾收集器(一)术语

    Garbage垃圾收集器的原理,在这篇博客中有讲到,可以拿来参考下, Getting Started with the G1 Garbage Collector(译) 另外在这篇博客中也有讲到很多垃圾 ...

  2. 《UNIX 网络编程 第二版》编译环境的搭建( 运行本专栏代码必读 )

    第一步:搭建基本的编译环境 安装gcc, g++, bulid-essential等编译软件 第二步:下载本书示例源码包 可在这里下载http://ishare.iask.sina.com.cn/f/ ...

  3. 九度OJ 1094:String Matching(字符串匹配) (计数)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1259 解决:686 题目描述: Finding all occurrences of a pattern in a text is a p ...

  4. 深入浅出剖析C语言函数指针与回调函数(一)【转】

    本文转载自:http://blog.csdn.net/morixinguan/article/details/65494239 关于静态库和动态库的使用和制作方法. http://blog.csdn. ...

  5. poj2586 Y2K Accounting Bug —— 枚举

    链接:http://poj.org/problem?id=2586 题意:大意是一个公司在12个月中,或固定盈余s,或固定亏损d.但记不得哪些月盈余,哪些月亏损,只能记得连续5个月的代数和总是亏损(和 ...

  6. hadoop集群部署后,遇到的问题记录

    1.  部署完,启动集群后,mapred-site.xml文件中配置没有生效 <property> <name>mapred.job.tracker</name> ...

  7. 如何创建WindowsService

    创建Windows Service可分为以下几步: 1. 创建一个“Windows Service”项目 2. 设置服务的相关属性,以确定服务的名称及工作机制 属性 设置 ServiceName 服务 ...

  8. Windows服务的快速搭建与调试(C#图解)

    Windows服务的快速搭建与调试(C#图解)   目录 一.什么是Windows 服务? 二.创建Windows 服务与安装/卸载批处理. 三.调试Windows 服务. 正文 一.什么是Windo ...

  9. hdu-5724 Chess(组合游戏)

    题目链接: Chess Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Pro ...

  10. Python:深浅拷贝

    导入模块: >>> import copy 深浅拷贝: >>> X = copy.copy(Y) #浅拷贝:只拷贝顶级的对象,或者说:父级对象 >>&g ...