Commit b62a3705 authored by 张媛's avatar 张媛

canvas组件添加

parent 38b86410
<!-- .storybook/preview-body.html -->
<!-- 渲染引擎 -->
<script src="//yun.duiba.com.cn/db_games/libs0924/fyge2023z.minSpine.js" crossorigin="anonymous"></script>
<canvas id="canvas-container"></canvas>
<!-- <canvas id="canvas-container"></canvas> -->
<style>
html {
font-size: 15px;
......@@ -10,7 +10,7 @@
<script>
window.FYGE = FYGE;
</script>
<script>
<!-- <script>
window.addEventListener("load", function () {
let canvas = document.getElementById("canvas-container")
canvas.style.height = document.body.clientHeight*(window.devicePixelRatio || 1)+"px";
......@@ -21,8 +21,8 @@
canvas,
750,
1624,
document.body.clientWidth,
document.body.clientHeight,
750,
1624,
FYGE.RENDERER_TYPE.CANVAS,
false,
false
......@@ -44,5 +44,5 @@
window.stage = stage;
})
</script>
</script> -->
const path = require('path');
module.exports = ({config, mode}) => {
config.module.rules.push({
test: /\.less$/,
test: /\.(less|css)$/,
loaders: ["style-loader", "css-loader", "less-loader"],
include: path.resolve(__dirname, '../')
});
......
export class CarouselComponent extends FYGE.Container {
bgContainer: FYGE.Container;
itemComponent: any;
itemWidth: number;
itemHeight: number;
vertical: boolean;
timer: any;
listContainer1: any;
listContainer2: any;
listWidth: number;
listHeight: number;
bgmask: FYGE.Graphics;
num: number;
k: number;//缓动系数,系数越大移动越快。在0-1之间。
totalStep: number;//累计移动了多少距离
stopStep: number;//滑动多少距离之后暂停一下
/**
*
* @param itemComponent //item组件
* @param itemWidth //每一个item的宽度
* @param itemHeight //每一个item的高度
* @param vertical //是否是垂直的
* @param num //要显示的个数
* @param k ////缓动系数,系数越大移动越快。在0-1之间
*/
constructor(itemComponent, itemWidth, itemHeight, vertical = false, num = 3, k = 0.24) {
super();
this.num = num;
this.totalStep = 0;
this.bgContainer = new FYGE.Container();
this.itemComponent = itemComponent;
this.itemHeight = itemHeight;
this.itemWidth = itemWidth;
this.vertical = vertical;
this.k = k;
if (this.vertical) {
this.stopStep = itemHeight;
this.bgmask = new FYGE.Graphics();
this.bgmask.beginFill();
this.bgmask.drawRect(0, 0, itemWidth, num * itemHeight)
this.bgmask.endFill();
} else {
this.stopStep = itemWidth;
this.bgmask = new FYGE.Graphics();
this.bgmask.beginFill();
this.bgmask.drawRect(0, 0, num * itemWidth, itemHeight)
this.bgmask.endFill();
}
}
//更新数据触发轮播
updateData(data) {
this.removeChildren();
this.bgContainer.removeChildren();
this.timer && clearTimeout(this.timer);
this.timer = null;
this.addChild(this.bgmask);
this.listContainer1 = new FYGE.Container();
this.listContainer2 = new FYGE.Container();
data.forEach((el, index) => {
let picture1 = new this.itemComponent(el);
let picture2 = new this.itemComponent(el);
if (!this.vertical) {
picture1.position.set(index * this.itemWidth, 0);
picture2.position.set(index * this.itemWidth, 0);
} else {
picture1.position.set(0, index * this.itemHeight);
picture2.position.set(0, index * this.itemHeight);
}
this.listContainer1.addChild(picture1);
this.listContainer2.addChild(picture2);
})
if (!this.vertical) {
this.listWidth = data.length * this.itemWidth;
this.listContainer1.position.set(0, 0)
this.listContainer2.position.set(data.length * this.itemWidth, 0)
} else {
this.listHeight = data.length * this.itemHeight;
this.listContainer1.position.set(0, 0)
this.listContainer2.position.set(0, data.length * this.itemHeight)
}
this.bgContainer.addChild(this.listContainer1);
this.bgContainer.addChild(this.listContainer2);
this.addChild(this.bgContainer);
this.bgContainer.mask = this.bgmask;
setTimeout(() => {
this.loop();
}, 1000)
}
loop() {
this.timer && clearTimeout(this.timer);
this.timer = null;
var step = (this.stopStep - this.totalStep) * this.k;
step = parseInt(step.toFixed(0))
step = step ? step : 1;
var sum = this.totalStep + step;
if (sum > this.stopStep) {
step = this.stopStep - this.totalStep;
}
// console.log(step)
if (!this.vertical) {
let x1 = this.listContainer1.x
let x2 = this.listContainer2.x
if (x1 + this.listWidth < 0) {
x1 = this.listWidth + (x1 + this.listWidth);
}
if (x2 + this.listWidth < 0) {
x2 = this.listWidth + (x2 + this.listWidth);
}
this.listContainer1.position.set(x1 - step, 0)
this.listContainer2.position.set(x2 - step, 0)
} else {
let y1 = this.listContainer1.y
let y2 = this.listContainer2.y
if (y1 + this.listHeight < 0) {
y1 = this.listHeight + (y1 + this.listHeight);
}
if (y2 + this.listHeight < 0) {
y2 = this.listHeight + (y2 + this.listHeight);
}
this.listContainer1.position.set(0, y1 - step)
this.listContainer2.position.set(0, y2 - step)
}
this.totalStep = this.totalStep + step
if (Math.abs(this.stopStep - this.totalStep) < 0.1) {
this.setTimeoutSelf(() => {
this.timer = this.setTimeoutSelf(() => {
this.loop()
}, 50)
}, 1000)
this.totalStep = 0;
} else {
this.timer = this.setTimeoutSelf(() => {
this.loop()
}, 50)
}
}
setTimeoutSelf(cb, interval) { // 实现setTimeout功能
let now = Date.now
let stime = now()
let etime = stime
let loop = () => {
var timeoutTimer = requestAnimationFrame(loop)
etime = now()
if (etime - stime >= interval) {
cb()
cancelAnimationFrame(timeoutTimer)
}
}
loop()
}
destroy() {
this.timer && clearTimeout(this.timer);
this.timer = null;
}
}
\ No newline at end of file
import React from 'react';
import { CarouselComponent } from "./carouseComponent";
import {createStage,isExistStage} from "../../common/createStage"
interface TestProps {
/**item组件*/
carouselItem: any
/**每一个item的宽度*/
itemWidth: number;
/**每一个item的高度*/
itemHeight: number;
/**是否是垂直的 */
vertical: boolean;
/**要显示的个数*/
num:number;
/** 缓动系数,系数越大移动越快。在0-1之间*/
k:number;
/**轮播的数据 */
data:any;
}
export const CarouselCom = (pros:TestProps)=>{
createStage();
isExistStage(()=>{
stage.removeAllChildren();
const carouseCom = new CarouselComponent(pros.carouselItem, pros.itemWidth, pros.itemHeight, pros.vertical, pros.num, pros.k);
stage.addChild(carouseCom);
carouseCom.position.set(10,20)
carouseCom.updateData(pros.data);
})
return (
<div></div>
)
}
......@@ -16,8 +16,7 @@ export class GoldCoinAni extends FYGE.Container {
* @param start 动效起点,[120,30]
* @param end 动效终点,[120,30]
* @param imgUrl 动效图片
* @param startCallback 第一个金币动效结束时的回调
* @param endCallback 最后一个金币动效完成时的回调
* @param callback 每一个金币动效结束时的回调
* @param isMinus true为向上凸,false为向下凹。
* @param curvature 0-1之间,0代表直线,1代表最弯
* @param goldNum 动效上面金币个数
......
import React from 'react';
import {GoldCoinAni} from "./goldCoinAni";
import {createStage,isExistStage} from "../../common/createStage"
interface TestProps {
/**设置主题色 */
label?: string;
/**动效起点,[120,30] */
start: Array<number>;
/**设置标题 */
test?: string;
end: Array<number>;
/**动效图片 */
imgUrl:string;
/**每一个金币动效结束时的回调 */
callBack: any;
/**true为向上凸,false为向下凹。 */
isMinus:boolean;
/** 0-1之间,0代表直线,1代表最弯*/
curvature:number;
/**动效上面金币个数 */
goldNum:number;
/**动效完成时间 */
time:number;
/**路线上的坐标串个数 */
coordNum?:number
}
const goldCoinReceiveAniCallback =(goldCode)=>{
console.log(goldCode);
}
export const GoldCoinCom = (pros:TestProps)=>{
stage.removeAllChildren();
const goldCoinAni = new GoldCoinAni([100, 200], [516, 200], "//yun.duiba.com.cn/spark/assets/b0709b25a9c0357c8d832e661345ee59c04b7aca.png", goldCoinReceiveAniCallback.bind(this), true, 0.2, 10, 400);
stage.addChild(goldCoinAni);
goldCoinAni.triggerAni();
createStage();
isExistStage(()=>{
stage.removeAllChildren();
const goldCoinAni = new GoldCoinAni(pros.start, pros.end, pros.imgUrl, pros.callBack, pros.isMinus, pros.curvature, pros.goldNum, pros.coordNum);
stage.addChild(goldCoinAni);
goldCoinAni.triggerAni();
})
return (
<div></div>
)
......
import React from 'react';
import {PolygonAxiosSystem} from "./polygonAxiosSystem";
import {createStage,isExistStage} from "../../common/createStage"
interface TestProps {
/**设置主题色 */
label?: string;
/**设置标题 */
test?: string;
/**坐标系统中心点x坐标 */
centerX: number;
/**坐标系统中心点y坐标 */
centerY: number;
/**坐标轴个数 */
axiosNum:number;
/**坐标节点个数 */
axiosNodeNum: number;
/**坐标系统的单位长度,一个刻度多长 */
unitLength:number;
/**坐标系统顺时针旋转多少度,原坐标系统基准轴水平向右,也是drawShape传的第一个数值所在的坐标轴*/
rotateDeg:number;
/**坐标轴名称,默认无 */
labels:Array<string>;
/**坐标系统样式*/
style:any;
}
export const PolygonSystemCom = (pros:TestProps)=>{
const polygonAxiosSystem = new PolygonAxiosSystem(
100, //坐标系统原点在弹窗中的x坐标
200, //坐标系统原点在弹窗中的y坐标
3, //3个坐标轴
3, //3个坐标节点
30, //坐标系统的单位长度,一个刻度多长。
90 //坐标系统顺时针旋转多少度,原坐标系统基准轴水平向右,也是drawShape传的第一个数值所在的坐标轴。
);
stage.addChild(polygonAxiosSystem);
polygonAxiosSystem.updateData(50 + "," + 50 + "," + 50);
export const PolygonSystemCom = (args:TestProps)=>{
createStage();
isExistStage(()=>{
const polygonAxiosSystem = new PolygonAxiosSystem(
args.centerX, //坐标系统原点在弹窗中的x坐标
args.centerY, //坐标系统原点在弹窗中的y坐标
args.axiosNum, //3个坐标轴
args.axiosNodeNum, //3个坐标节点
args.unitLength, //坐标系统的单位长度,一个刻度多长。
args.rotateDeg,//坐标系统顺时针旋转多少度,原坐标系统基准轴水平向右,也是drawShape传的第一个数值所在的坐标轴。
args.labels,
args.style
);
stage.removeAllChildren();
stage.addChild(polygonAxiosSystem);
polygonAxiosSystem.updateData(50 + "," + 50 + "," + 50);
})
return (
<div></div>
)
......
import React from 'react';
import { CarouselCom } from '../canvasCom/carouselCom/carouselCom';
class carouselItem extends FYGE.Container {
constructor(data) {
super();
let itemBg = FYGE.Sprite.fromUrl("//yun.duiba.com.cn/spark/assets/029a53c6dc60b0c3a4538862cbeb0e3a329152f4.png");
this.addChild(itemBg);
let itemName = new FYGE.TextField();
itemName.text = data.name;
itemName.size = 24;
itemName.fillColor = "#000000";
itemName.textAlign = FYGE.TEXT_ALIGN.CENTER;
itemName.textWidth = itemBg.width;
this.addChild(itemName);
itemName.position.set(0, 200);
let itemImg = FYGE.Sprite.fromUrl(data.icon);
itemBg.addChild(itemImg);
itemImg.width = 183;
itemImg.height = 183;
itemImg.position.set(5, 5);
}
}
export default {
component: CarouselCom,
title: 'Canvas组件/轮播组件',
//👇 Creates specific argTypes
argTypes: {
backgroundColor: { control: 'color' },
},
args: {
//👇 Now all Button stories will be primary.
primary: true,
},
};
//👇 We create a “template” of how args map to rendering
const Template = (args) => <CarouselCom {...args} />;
//👇 Each story then reuses that template
export const Primary = Template.bind({});
Primary.parameters = {
layout: 'centered',
};
Primary.args = {
primary: true,
label: '金币动效',
carouselItem:carouselItem,
itemWidth:204,
itemHeight:242,
vertical:false,
num:3,
k:0.3,
data:[
{
"rule": "ru_1",
"name": "飞科剃须刀1",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 10000,
"stock": 111111111111,
"channel":0
},
{
"rule": "ru_1",
"name": "飞科剃须刀2",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 0,
"channel":0
},
{
"rule": "ru_1",
"name": "飞科剃须刀3",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 0,
"channel":0
},
{
"rule": "ru_1",
"name": "飞科剃须刀4",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 0,
"channel":2
},
{
"rule": "ru_1",
"name": "飞科剃须刀5",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 0,
"channel":2
},
{
"rule": "ru_1",
"name": "飞科剃须刀6",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 0,
"channel":1
},
{
"rule": "ru_1",
"name": "飞科剃须刀7",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 1,
"channel":0
},
{
"rule": "ru_1",
"name": "飞科剃须刀8",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 1,
"channel":2
},
{
"rule": "ru_1",
"name": "飞科剃须刀0",
"icon": "//yun.duiba.com.cn/polaris/一波1.8644720387778750b4af371deb5f86562897aab2.jpg",
"coins": 100,
"stock": 1,
"channel":2
}
]
};
......@@ -2,7 +2,7 @@ import React from 'react';
import { GoldCoinCom } from '../canvasCom/goldCoinCom/GoldCoinCom.tsx';
export default {
component: GoldCoinCom,
title: 'Canvas组件/GoldCoin',
title: 'Canvas组件/金币动效',
//👇 Creates specific argTypes
argTypes: {
backgroundColor: { control: 'color' },
......@@ -12,15 +12,27 @@ export default {
primary: true,
},
};
const goldCoinReceiveAniCallback =(goldCode)=>{
console.log(goldCode);
}
//👇 We create a “template” of how args map to rendering
const Template = (args) => <GoldCoinCom {...args} />;
//👇 Each story then reuses that template
export const Primary = Template.bind({});
Primary.parameters = {
layout: 'centered',
};
Primary.args = {
primary: true,
label: 'GoldCoin',
label: '金币动效',
start:[100, 200],
end:[516, 200],
imgUrl:"//yun.duiba.com.cn/spark/assets/eed18886070638f6119f04ba849cf93e23e0d186.png",
callBack: goldCoinReceiveAniCallback.bind(this),
isMinus:true,
curvature:0.2,
goldNum:10,
time:400
};
......@@ -2,7 +2,7 @@ import React from 'react';
import { PolygonSystemCom } from '../canvasCom/polygonSystemCom/PolygonSystemCom.tsx';
export default {
component: PolygonSystemCom,
title: 'Canvas组件/polygonSystem',
title: 'Canvas组件/多变形坐标系统',
//👇 Creates specific argTypes
argTypes: {
backgroundColor: { control: 'color' },
......@@ -18,9 +18,32 @@ const Template = (args) => <PolygonSystemCom {...args} />;
//👇 Each story then reuses that template
export const Primary = Template.bind({});
Primary.parameters = {
layout: 'centered',
};
Primary.args = {
primary: true,
label: 'Button',
label: '多变形坐标系统',
centerX:100, //坐标系统原点在弹窗中的x坐标
centerY:200, //坐标系统原点在弹窗中的y坐标
axiosNum:3, //3个坐标轴
axiosNodeNum:3, //3个坐标节点
unitLength:30, //坐标系统的单位长度,一个刻度多长。
rotateDeg:90,
labels:["haha","heihei"],
style:{
gridStyle: {
color: 0xb46e42,
width: 1,
},
shapeStyle: {
color: 0x95d176,
alpha: 0.8,
},
labelStyle: {
color: "#7c3c23",
size: 24,
},
}
};
export const createStage = ()=>{
const height = document.body.clientHeight*(window.devicePixelRatio || 1)||1624;
const width = document.body.clientWidth*(window.devicePixelRatio || 1)||750;
console.log("ssssss",document.body.clientHeight,document.body.clientWidth)
let canvas = document.getElementById("canvas-container")
if(!canvas){
canvas = document.createElement("canvas");
canvas.setAttribute("id","canvas-container")
canvas.setAttribute("height",height+"");
canvas.setAttribute("width",width+"");
document.body.appendChild(canvas);
}else{
return;
}
var stage = new FYGE.Stage(
canvas,
width,
height,
document.body.clientWidth,
document.body.clientHeight,
FYGE.RENDERER_TYPE.CANVAS,
false,
false
)
//点击事件绑定
var mouseEvent = stage.onMouseEvent.bind(stage);
canvas.addEventListener("touchstart",mouseEvent,false);
canvas.addEventListener("touchmove",mouseEvent,false);
canvas.addEventListener("touchend",mouseEvent,false);
canvas.addEventListener("click",mouseEvent,false);
function loop() {
stage.flush();
FYGE.Tween.flush();
requestAnimationFrame(loop);
}
loop();
window.stage = stage;
}
export const isExistStage = (cb)=>{
if(stage){
cb();
}else{
setTimeout(isExistStage,100);
}
}
export const clearStage = ()=>{
let canvas = document.getElementById("canvas-container");
if(canvas)document.body.removeChild(canvas);
}
\ No newline at end of file
import React from 'react';
import "./danma.less";
import DanmaCtrl from './danmaCtrl'
import DanmaCtrl from './danmaCtrl';
import {clearStage} from "../../common/createStage"
export const Danma = (data) => {
clearStage();
const Danma = DanmaCtrl(data.DanmaItem, data.danmaData, data.speed, data.width, data.height)
return (
<>
......
.testButton{
display: inline-block;
background-color: aquamarine;
width: 50px;
height: 50px;
.testButton-inner{
display: inline-block;
background-color: red;
width: 20px;
height: 20px;
border-radius: 10px;
}
}
import React from 'react';
import "./testSpan.less";
interface TestProps {
/**设置主题色 */
label?: string;
/**设置标题 */
test?: string;
}
export const TestSpan = (pros:TestProps)=>{
return (
<span className="testButton">
<span className = "testButton-inner">
</span>
{pros.label}
<span>
{pros.test}
</span>
</span>
)
}
\ No newline at end of file
import React from 'react';
import { Button } from '@storybook/react/demo';
export default {
component: Button,
title: 'React组件/Button',
//👇 Creates specific argTypes
argTypes: {
backgroundColor: { control: 'color' },
},
args: {
//👇 Now all Button stories will be primary.
primary: true,
},
};
//👇 We create a “template” of how args map to rendering
const Template = (args) => <Button {...args} />;
//👇 Each story then reuses that template
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Button',
};
......@@ -4,7 +4,7 @@ import DanmaItem from '../reactCom/danma/danmaItem';
export default {
component: Danma,
title: 'React组件/Danma',
title: 'React组件/弹幕',
};
let danmaAvatars = ["//yun.duiba.com.cn/polaris/1022.5d0247352e3f1a068cd812df9051079b111ef0a5.jpg"
, "//yun.duiba.com.cn/polaris/1022.5d0247352e3f1a068cd812df9051079b111ef0a5.jpg"
......@@ -75,13 +75,19 @@ let width = 400
let height = 60
//@ts-ignore
const Template = () => <Danma DanmaItem={DanmaItem} danmaData={danmaData} speed={speed} width={width} height={height} />;
// const Template = () => <Danma DanmaItem={DanmaItem} danmaData={danmaData} speed={speed} width={width} height={height} />;
const Template = (args) => <Danma {...args}/>;
export const Primary = Template.bind({});
Primary.args = {
primary: false,
label: 'Danma',
DanmaItem: DanmaItem,
danmaData: danmaData,
speed:speed,
width:width,
height:height
};
Primary.parameters = {
layout: 'centered',
......
import React from 'react';
import { TestSpan } from "../reactCom/testSpan/testSpan";
export default {
component: TestSpan,
title: 'React组件/TestSpan',
argTypes: {
variant: {
options: ['TestSpan', 'Default'],
control: { label: 'radio' }
}
}
};
//👇 We create a “template” of how args map to rendering
const Template = (args) => <TestSpan {...args} />;
//👇 Each story then reuses that template
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'TestSpan',
};
Primary.parameters = {
layout: 'centered',
};
export const Default = Template.bind({});
Default.args = {
primary: true,
label: 'Default',
};
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment