在react中用canvas作一個電影院選座功能

前沿:項目採用create-react-app腳手架,就是作了一個效果因此只有一個頁面可是也用了react-router-dom路由把details做爲path=’/'首頁了。css

效果圖:react

1、App.jsjson

import React from 'react';

import {BrowserRouter,Route} from 'react-router-dom'

import Details from './routes/Details'

function App() {

  return (

    <div className="App">

      <BrowserRouter>

        <Route path='/' component={Details}></Route>

      </BrowserRouter>

    </div>

  );

}



export default App;

這是入口文件的代碼內容canvas

 

2、Details.jsxreact-router

import React,{Component} from 'react';
import './Details.css';
import Footer from './Footer';
import SeatSelector from './SeatSelector'
class Details extends Component {
	
      state = {
            selectSeat:[]
      }
      addSeat = (seat)=>{
            this.setState(prevState=>({
                  selectSeat:[...prevState.selectSeat,seat]
            }))
      }
      removeSeat = (id)=>{
            this.setState({
                selectSeat:this.state.selectSeat.filter(seat=>seat.id !== id)
            })
      }
	render() {
        const {selectSeat} = this.state;
		return (
			<div>
             	<header>
             		<div className='header-container'>
             			<h2>決戰時刻</h2>
             			<h3>今天 09-21 15:40~18:00 (國語 2D)</h3>
             		</div>
             	</header>
             	<div className='seat'>
             	    <SeatSelector selected={selectSeat} onAdd={this.addSeat} onRemove={this.removeSeat}/>
             	</div>
             	<Footer data={selectSeat} onRemove={this.removeSeat}/>
			</div>
		);
	}
}

export default Details;

這是效果的首頁的東西了,分爲3個部分(頭部,中間canvas部分,底部),頭部基本隨便寫,底部有一個選座顯示幾排幾座的效果,主要是中間部分app

 

3、SeatSelector.jsxdom

import React,{Component} from 'react';
import {data} from './mock/data.json';
const SET_WIDTH = 50;
const SET_HEIGHT = 50;

const lastSeat = data[data.length-1];
const canvas_width = lastSeat.x*SET_WIDTH;
const canvas_height = lastSeat.y*SET_HEIGHT;

class Details extends Component {
	componentDidMount(){
        this.ctx = this.refs.canvas.getContext('2d');
        const emptyImg = new Image();
        const selectImg = new Image();
        const soldImg = new Image();
        let count = 0;
        const loadCallback = ()=>{
            count++;
            if(count===3){
                this.emptyImg = emptyImg;
                this.selectImg = selectImg;
                this.soldImg = soldImg;
                 this.drawSeat();
            }
        }
        emptyImg.onload = loadCallback;
        selectImg.onload = loadCallback;
        soldImg.onload = loadCallback;

        emptyImg.src = './empty.png';
        selectImg.src = './select.jpg';
        soldImg.src = './sold.jpg';
    }
    componentDidUpdate(){
        this.ctx.clearRect(0,0,canvas_width,canvas_height)
        this.drawSeat();
        this.drawSelectSeat();
    }
    drawSeat(){
        const seatData = data;
        seatData.forEach((item,index)=>{
            const {isSold,x,y} = item;
            const offsetLeft = (x-1)*SET_WIDTH;
            const offsetTop = (y-1)*SET_WIDTH;
            if(isSold){
               this.ctx.drawImage(this.soldImg,offsetLeft,offsetTop,SET_WIDTH,SET_HEIGHT);
            }else{
               this.ctx.drawImage(this.emptyImg,offsetLeft,offsetTop,SET_WIDTH,SET_HEIGHT);
            }
        })
    }
    drawSelectSeat = ()=>{

        const {selected} = this.props;
        selected.forEach((item,index)=>{
            const {isSold,x,y} = item;
            const offsetLeft = (x-1)*SET_WIDTH;
            const offsetTop = (y-1)*SET_WIDTH;
            this.ctx.drawImage(this.selectImg,offsetLeft,offsetTop,SET_WIDTH,SET_HEIGHT);
        })

    }
    clickSeat = (e)=>{
        
        let offset = this.refs.canvas.getBoundingClientRect()
        let pageX = e.pageX - offset.left;
        let pageY = e.pageY - offset.top;

        let xPos = Math.ceil(pageX/SET_WIDTH);
        let yPos = Math.ceil(pageY/SET_HEIGHT);

        let seat = data.find(seat=>seat.x===xPos && seat.y===yPos);

        if( seat.isSold  ){
            return ;
        }

        const selectIndex = this.props.selected.findIndex(item=>item.id === seat.id);
        if(selectIndex>-1){
            this.props.onRemove(seat.id);
        }else{
            if(this.props.selected.length >= 6){
                alert("不能超過6個");
            }else{
                this.props.onAdd(seat);
            }
        }

    }
	render() {
		return (
			<div>
             	<canvas onClick={this.clickSeat}  ref='canvas' width={canvas_width} height={canvas_height}/>    
			</div>
		);
	}

}

export default Details;

這是中間canvas比較重要的一塊了,你們能夠看看代碼了this

4、Footer.jsxspa

import React from 'react';

import './footer.css';

const Footer = ({data,onRemove}) => {

  return (

    <footer>

     <div className='seatNum'>

     <ul>



     {

     data.map(seat=>(

<li key={seat.id} onClick={()=>onRemove(seat.id)}>

     <p>{seat.y}排{seat.x}座</p>

     <p>42.7元</p>

     </li>

     ))

     }



     </ul>

     </div>

     <div className='seatSelect'>請先選座</div>

    </footer>

  )

}



export default Footer;

這是底部代碼code

相關文章
相關標籤/搜索