例子
1.自定义数据
var data1 = [['aa1','aa2','aa3','aa4','aa5','aa6'],['bb1','bb2','bb3','bb4','bb5','bb6'],['cc1','cc2','cc3','cc4','cc5','cc6']];
naming: {//设置行列等信息 top: false, //不显示顶部横坐标(行) // rows: ['3', '2', '1'], // columns: ['A', 'B', 'C', 'G', 'D', 'F'], getLabel: function(character, row, column) { //返回房间信息 return column; }, getData:function(dataList){ console.log(dataList) return dataList; }, data:data1 },
seats[id] = new seat({ id : id, label : naming.data[row][column] , // label : overrideLabel ? overrideLabel : naming.getLabel(character, naming.rows[row], naming.columns[column]), row : row, column : column, character : character });
4.源码修改,25行左右 加入data参数
settings = { animate : false, //requires jQuery UI naming : { top : true, left : true, getId : function(character, row, column) { return row + '_' + column; }, getLabel : function (character, row, column) { return column; }, data:[] },
if (this.data('seatCharts')) { // console.log(this.data('seatCharts')) // return this.data('seatCharts'); // console.log(setup) // console.log(setup.legend.items) // console.log(this.data('seatCharts')) var ary = setup.legend.items; ary.splice(0,ary.length); this.empty(); }完整实例
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>test</title> <link rel="stylesheet" type="text/css" href="css/roomchartcommon.css" /> <script type="text/javascript" src="js/jquery-1.11.2.js"></script> <script type="text/javascript" src="js/jquery.seat-charts.js"></script> <script type="text/javascript"> var price = 100; //房间价 var beforeroom; var $cart = $('#rooms_selected'), //房间区 $rooms_num = $('#rooms_num'), //房间数 $total_price = $('#rooms_price'); //总金额 $roomNo = $('#roomNo');//房间号 $roomMsg = $('#roomMsg');//房间信息 var sc ; var data1 = [['aa1','aa2','aa3','aa4','aa5','aa6'],['bb1','bb2','bb3','bb4','bb5','bb6'], ['cc1','cc2','cc3','cc4','cc5','cc6']]; var data2 = [['dd1','dd2','dd3','dd4','dd5','dd6'],['ee1','ee2','ee3','ee4','ee5','ee6'], ['ff1','ff2','ff3','ff4','ff5','ff6']]; $(document).ready(function() { initchart(data1); }); function initchart(dataList){ sc = $('#room_area').seatCharts({ map: [//房间结构图 f 代表已入住;e 代表未入住; 下划线 "_" 代表过道 'ffffff', 'eeeeee', 'ffeeee' ], seats: {//设置已入住和未入住相关属性 f: { price: 125, classes: 'first-class', category: '已入住' }, e: { price: 70, classes: 'economy-class', category: '未入住' } }, naming: {//设置行列等信息 top: false, //不显示顶部横坐标(行) // rows: ['3', '2', '1'], // columns: ['A', 'B', 'C', 'G', 'D', 'F'], getLabel: function(character, row, column) { //返回房间信息 return column; }, getData:function(dataList){ console.log(dataList) return dataList; }, data:dataList }, legend: {//定义图例 node: $('#roomlegend'), items: [ ['f', 'available', '未入住'], ['e', 'available', '将到期'], ['f', 'unavailable', '已入住'] ] }, click: function() { if (this.status() == 'available') { //若为可选状态,添加响应事件 var roomNoText = $('<li>' + this.settings.label + '号</li>') .attr('id', 'cart-item-' + this.settings.id) .data('seatId', this.settings.id).text(); $roomNo.text(roomNoText); var roomMsgHtml = '<span>没有入住信息</span><br><input type="button" class="roominbtn" value="入住"/>'; $roomMsg.html(roomMsgHtml); return 'selected'; $('<li>' + (this.settings.row + 1) + this.settings.label + '号</li>') .attr('id', 'cart-item-' + this.settings.id) .data('seatId', this.settings.id) .appendTo($cart); $rooms_num.text(sc.find('selected').length + 1); //统计选票数量 $total_price.text(getTotalPrice(sc) + price);//计算票价总金额 return 'selected'; } else if (this.status() == 'selected') { //若为选中状态 $rooms_num.text(sc.find('selected').length - 1);//更新票数量 $total_price.text(getTotalPrice(sc) - price);//更新票价总金额 $('#cart-item-' + this.settings.id).remove();//删除已预订座位 return 'available'; } else if (this.status() == 'unavailable') { //若为损坏状态 var roomNoText = $('<li>' + this.settings.label + '号</li>') .attr('id', 'cart-item-' + this.settings.id) .data('seatId', this.settings.id).text(); console.log(roomNoText); $roomNo.text(roomNoText); var roomMsgText = "张三、李四、王五、马六"; $roomMsg.text(roomMsgText); return 'unavailable'; } else { return this.style(); } } }); //设置已售出的座位 sc.get(['3_03', '2_05']).status('unavailable'); } function refresh(){ // console.log(sc); // sc.dataReload(data2) initchart(data2) } </script> </head> <body> <button style="float:right;width:150px;height:30px;" onclick="refresh()">刷新图表</button> <div class="roomcontent"> <div id="room_area"> </div> <div id="roomlegend" class='of'></div> <div id="roomdetail"> <h3>房间详细信息</h3> <div id="roomNo"> </div> <div id="roomMsg"> </div> </div> </div> </body> </html>
/* * jQuery-Seat-Charts v1.1.0 */ (function($) { $.fn.seatCharts = function (setup) { //if there's seatCharts object associated with the current element, return it if (this.data('seatCharts')) { // console.log(this.data('seatCharts')) // return this.data('seatCharts'); // console.log(setup) // console.log(setup.legend.items) // console.log(this.data('seatCharts')) var ary = setup.legend.items; ary.splice(0,ary.length); this.empty(); } var fn = this, seats = {}, seatIds = [], legend, settings = { animate : false, //requires jQuery UI naming : { top : true, left : true, getId : function(character, row, column) { return row + '_' + column; }, getLabel : function (character, row, column) { return column; }, data:[] }, legend : { node : null, items : [] }, click : function() { if (this.status() == 'available') { return 'selected'; } else if (this.status() == 'selected') { return 'available'; } else { return this.style(); } }, focus : function() { if (this.status() == 'available') { return 'focused'; } else { return this.style(); } }, blur : function() { return this.status(); }, seats : {} }, //seat will be basically a seat object which we'll when generating the map seat = (function(seatCharts, seatChartsSettings) { return function (setup) { var fn = this; fn.settings = $.extend({ status : 'available', //available, unavailable, selected style : 'available', //make sure there's an empty hash if user doesn't pass anything data : seatChartsSettings.seats[setup.character] || {} //anything goes here? }, setup); fn.settings.$node = $('<div></div>'); fn.settings.$node .attr({ id : fn.settings.id, role : 'checkbox', 'aria-checked' : false, focusable : true, tabIndex : -1 //manual focus }) .text(fn.settings.label) .addClass(['seatCharts-seat', 'seatCharts-cell', 'available'].concat( //let's merge custom user defined classes with standard JSC ones fn.settings.classes, typeof seatChartsSettings.seats[fn.settings.character] == "undefined" ? [] : seatChartsSettings.seats[fn.settings.character].classes ).join(' ')); //basically a wrapper function fn.data = function() { return fn.settings.data; }; fn.char = function() { return fn.settings.character; }; fn.node = function() { return fn.settings.$node; }; /* * Can either set or return status depending on arguments. * * If there's no argument, it will return the current style. * * If you pass an argument, it will update seat's style */ fn.style = function() { return arguments.length == 1 ? (function(newStyle) { var oldStyle = fn.settings.style; //if nothing changes, do nothing if (newStyle == oldStyle) { return; } //focused is a special style which is not associated with status fn.settings.status = newStyle != 'focused' ? newStyle : fn.settings.status; fn.settings.$node .attr('aria-checked', newStyle == 'selected'); //if user wants to animate status changes, let him do this seatChartsSettings.animate ? fn.settings.$node.switchClass(oldStyle, newStyle, 200) : fn.settings.$node.removeClass(oldStyle).addClass(newStyle); return fn.settings.style = newStyle; })(arguments[0]) : fn.settings.style; }; //either set or retrieve fn.status = function() { return fn.settings.status = arguments.length == 1 ? fn.style(arguments[0]) : fn.settings.status; }; //using immediate function to convienietly get shortcut variables (function(seatSettings, character, seat) { //attach event handlers $.each(['click', 'focus', 'blur'], function(index, callback) { //we want to be able to call the functions for each seat object fn[callback] = function() { if (callback == 'focus') { //if there's already a focused element, we have to remove focus from it first if (seatCharts.attr('aria-activedescendant') !== undefined) { seats[seatCharts.attr('aria-activedescendant')].blur(); } seatCharts.attr('aria-activedescendant', seat.settings.id); seat.node().focus(); } /* * User can pass his own callback function, so we have to first check if it exists * and if not, use our default callback. * * Each callback function is executed in the current seat context. */ return fn.style(typeof seatSettings[character][callback] === 'function' ? seatSettings[character][callback].apply(seat) : seatChartsSettings[callback].apply(seat)); }; }); //the below will become seatSettings, character, seat thanks to the immediate function })(seatChartsSettings.seats, fn.settings.character, fn); fn.node() //the first three mouse events are simple .on('click', fn.click) .on('mouseenter', fn.focus) .on('mouseleave', fn.blur) //keydown requires quite a lot of logic, because we have to know where to move the focus .on('keydown', (function(seat, $seat) { return function (e) { var $newSeat; //everything depends on the pressed key switch (e.which) { //spacebar will just trigger the same event mouse click does case 32: e.preventDefault(); seat.click(); break; //UP & DOWN case 40: case 38: e.preventDefault(); /* * This is a recursive, immediate function which searches for the first "focusable" row. * * We're using immediate function because we want a convenient access to some DOM elements * We're using recursion because sometimes we may hit an empty space rather than a seat. * */ $newSeat = (function findAvailable($rows, $seats, $currentRow) { var $newRow; //let's determine which row should we move to if (!$rows.index($currentRow) && e.which == 38) { //if this is the first row and user has pressed up arrow, move to the last row $newRow = $rows.last(); } else if ($rows.index($currentRow) == $rows.length-1 && e.which == 40) { //if this is the last row and user has pressed down arrow, move to the first row $newRow = $rows.first(); } else { //using eq to get an element at the desired index position $newRow = $rows.eq( //if up arrow, then decrement the index, if down increment it $rows.index($currentRow) + (e.which == 38 ? (-1) : (+1)) ); } //now that we know the row, let's get the seat using the current column position $newSeat = $newRow.find('.seatCharts-seat,.seatCharts-space').eq($seats.index($seat)); //if the seat we found is a space, keep looking further return $newSeat.hasClass('seatCharts-space') ? findAvailable($rows, $seats, $newRow) : $newSeat; })($seat //get a reference to the parent container and then select all rows but the header .parents('.seatCharts-container') .find('.seatCharts-row:not(.seatCharts-header)'), $seat //get a reference to the parent row and then find all seat cells (both seats & spaces) .parents('.seatCharts-row:first') .find('.seatCharts-seat,.seatCharts-space'), //get a reference to the current row $seat.parents('.seatCharts-row:not(.seatCharts-header)') ); //we couldn't determine the new seat, so we better give up if (!$newSeat.length) { return; } //remove focus from the old seat and put it on the new one seat.blur(); seats[$newSeat.attr('id')].focus(); $newSeat.focus(); //update our "aria" reference with the new seat id seatCharts.attr('aria-activedescendant', $newSeat.attr('id')); break; //LEFT & RIGHT case 37: case 39: e.preventDefault(); /* * The logic here is slightly different from the one for up/down arrows. * User will be able to browse the whole map using just left/right arrow, because * it will move to the next row when we reach the right/left-most seat. */ $newSeat = (function($seats) { if (!$seats.index($seat) && e.which == 37) { //user has pressed left arrow and we're currently on the left-most seat return $seats.last(); } else if ($seats.index($seat) == $seats.length -1 && e.which == 39) { //user has pressed right arrow and we're currently on the right-most seat return $seats.first(); } else { //simply move one seat left or right depending on the key return $seats.eq($seats.index($seat) + (e.which == 37 ? (-1) : (+1))); } })($seat .parents('.seatCharts-container:first') .find('.seatCharts-seat:not(.seatCharts-space)')); if (!$newSeat.length) { return; } //handle focus seat.blur(); seats[$newSeat.attr('id')].focus(); $newSeat.focus(); //update our "aria" reference with the new seat id seatCharts.attr('aria-activedescendant', $newSeat.attr('id')); break; default: break; } }; })(fn, fn.node())); //.appendTo(seatCharts.find('.' + row)); } })(fn, settings); fn.addClass('seatCharts-container'); //true -> deep copy! $.extend(true, settings, setup); //Generate default row ids unless user passed his own settings.naming.rows = settings.naming.rows || (function(length) { var rows = []; for (var i = 1; i <= length; i++) { rows.push(i); } return rows; })(settings.map.length); //Generate default column ids unless user passed his own settings.naming.columns = settings.naming.columns || (function(length) { var columns = []; for (var i = 1; i <= length; i++) { columns.push("0"+i); } return columns; })(settings.map[0].split('').length); if (settings.naming.top) { var $headerRow = $('<div></div>') .addClass('seatCharts-row seatCharts-header'); if (settings.naming.left) { $headerRow.append($('<div></div>').addClass('seatCharts-cell')); } $.each(settings.naming.columns, function(index, value) { $headerRow.append( $('<div></div>') .addClass('seatCharts-cell') .text(value) ); }); } fn.append($headerRow); //do this for each map row $.each(settings.map, function(row, characters) { var $row = $('<div></div>').addClass('seatCharts-row'); if (settings.naming.left) { $row.append( $('<div></div>') .addClass('seatCharts-cell seatCharts-space') .text(settings.naming.rows[row]) ); } /* * Do this for each seat (letter) * * Now users will be able to pass custom ID and label which overwrite the one that seat would be assigned by getId and * getLabel * * New format is like this: * a[ID,label]a[ID]aaaaa * * So you can overwrite the ID or label (or both) even for just one seat. * Basically ID should be first, so if you want to overwrite just label write it as follows: * a[,LABEL] * * Allowed characters in IDs areL 0-9, a-z, A-Z, _ * Allowed characters in labels are: 0-9, a-z, A-Z, _, ' ' (space) * */ $.each(characters.match(/[a-z_]{1}(\[[0-9a-z_]{0,}(,[0-9a-z_ ]+)?\])?/gi), function (column, characterParams) { var matches = characterParams.match(/([a-z_]{1})(\[([0-9a-z_ ,]+)\])?/i), //no matter if user specifies [] params, the character should be in the second element character = matches[1], //check if user has passed some additional params to override id or label params = typeof matches[3] !== 'undefined' ? matches[3].split(',') : [], //id param should be first overrideId = params.length ? params[0] : null, //label param should be second overrideLabel = params.length === 2 ? params[1] : null; $row.append(character != '_' ? //if the character is not an underscore (empty space) (function(naming) { //console.log(naming); //so users don't have to specify empty objects // console.log(naming); // console.log("character"+naming.getLabel(character, naming.rows[row], naming.columns[column])); // console.log("row"+row); // console.log(column); // console.log(naming.data) settings.seats[character] = character in settings.seats ? settings.seats[character] : {}; var id = overrideId ? overrideId : naming.getId(character, naming.rows[row], naming.columns[column]); seats[id] = new seat({ id : id, label : naming.data[row][column] , // label : overrideLabel ? overrideLabel : naming.getLabel(character, naming.rows[row], naming.columns[column]), row : row, column : column, character : character }); seatIds.push(id); return seats[id].node(); })(settings.naming) : //this is just an empty space (_) $('<div></div>').addClass('seatCharts-cell seatCharts-space') ); }); fn.append($row); }); //if there're any legend items to be rendered settings.legend.items.length ? (function(legend) { //either use user-defined container or create our own and insert it right after the seat chart div var $container = (legend.node || $('<div></div').insertAfter(fn)) .addClass('seatCharts-legend'); var $ul = $('<ul></ul>') .addClass('seatCharts-legendList') .appendTo($container); $.each(legend.items, function(index, item) { $ul.append( $('<li></li>') .addClass('seatCharts-legendItem') .append( $('<div></div>') //merge user defined classes with our standard ones .addClass(['seatCharts-seat', 'seatCharts-cell', item[1]].concat( settings.classes, typeof settings.seats[item[0]] == "undefined" ? [] : settings.seats[item[0]].classes).join(' ') ) ) .append( $('<span></span>') .addClass('seatCharts-legendDescription') .text(item[2]) ) ); }); return $container; })(settings.legend) : null; fn.attr({ tabIndex : 0 }); //when container's focused, move focus to the first seat fn.focus(function() { if (fn.attr('aria-activedescendant')) { seats[fn.attr('aria-activedescendant')].blur(); } fn.find('.seatCharts-seat:not(.seatCharts-space):first').focus(); seats[seatIds[0]].focus(); }); //public methods of seatCharts fn.data('seatCharts', { seats : seats, seatIds : seatIds, //set for one, set for many, get for one status: function() { var fn = this; return arguments.length == 1 ? fn.seats[arguments[0]].status() : (function(seatsIds, newStatus) { return typeof seatsIds == 'string' ? fn.seats[seatsIds].status(newStatus) : (function() { $.each(seatsIds, function(index, seatId) { fn.seats[seatId].status(newStatus); }); })(); })(arguments[0], arguments[1]); }, each : function(callback) { var fn = this; for (var seatId in fn.seats) { if (false === callback.call(fn.seats[seatId], seatId)) { return seatId;//return last checked } } return true; }, node : function() { var fn = this; //basically create a CSS query to get all seats by their DOM ids return $('#' + fn.seatIds.join(',#')); }, find : function(query) {//D, a.available, unavailable var fn = this; var seatSet = fn.set(); //user searches just for a particual character return query.length == 1 ? (function(character) { fn.each(function() { if (this.char() == character) { seatSet.push(this.settings.id, this); } }); return seatSet; })(query) : (function() { //user runs a more sophisticated query, so let's see if there's a dot return query.indexOf('.') > -1 ? (function() { //there's a dot which separates character and the status var parts = query.split('.'); fn.each(function(seatId) { if (this.char() == parts[0] && this.status() == parts[1]) { seatSet.push(this.settings.id, this); } }); return seatSet; })() : (function() { fn.each(function() { if (this.status() == query) { seatSet.push(this.settings.id, this); } }); return seatSet; })(); })(); }, set : function set() {//inherits some methods var fn = this; return { seats : [], seatIds : [], length : 0, status : function() { var args = arguments, that = this; //if there's just one seat in the set and user didn't pass any params, return current status return this.length == 1 && args.length == 0 ? this.seats[0].status() : (function() { //otherwise call status function for each of the seats in the set $.each(that.seats, function() { this.status.apply(this, args); }); })(); }, node : function() { return fn.node.call(this); }, each : function() { return fn.each.call(this, arguments[0]); }, get : function() { return fn.get.call(this, arguments[0]); }, find : function() { return fn.find.call(this, arguments[0]); }, set : function() { return set.call(fn); }, push : function(id, seat) { this.seats.push(seat); this.seatIds.push(id); ++this.length; } }; }, //get one object or a set of objects get : function(seatsIds) { var fn = this; return typeof seatsIds == 'string' ? fn.seats[seatsIds] : (function() { var seatSet = fn.set(); $.each(seatsIds, function(index, seatId) { if (typeof fn.seats[seatId] === 'object') { seatSet.push(seatId, fn.seats[seatId]); } }); return seatSet; })(); }, dataReload : function(data){ // console.log(this) // console.log(data); } }); return fn.data('seatCharts'); } })(jQuery);