使用例:ECサイト風スライサー

SpreadJSを使用して様々なUIを持ったスライサーを作成できます。

このページで表示されているデモはECサイトでよく見られるフィルタ機能を再現したものです。 この機能を使用することで、エンドユーザーは興味がある商品を簡単に探し出すことができるようになります。
var dataNames = ["Image", "Description", "Brand", "Price", "Internal Memory", "Network", "Avg. Customer Review", "ShipToChina"]; //"size", var datas = [["NOKIA521.jpg", "Nokia Lumia 521 T-Mobile Cell Phone - White", "Nokia", "49.99", "16", "3G", "4", true], ["LG450.jpg", "LG 450 Black - No Contract (T-Mobile)", "LG", "29.99", "4", "3G", "4", true], ["LGC365.jpg", "LG Xpression C395 Unlocked GSM Slider Cell Phone with Touchscreen + Full QWERTY Keyboard - Red", "LG", "49.99", "32", "3G", "3.5", false], ["BLUPink.jpg", "BLU Dash JR W D141w Unlocked GSM Dual-SIM Android Cell Phone - Pink", "BLU", "18.99", "4", "3G", "4", true], ["BLUWhite.jpg", "BLU Dash JR W D141w Unlocked GSM Dual-SIM Android Cell Phone - White", "BLU", "129.99", "32", "4G", "3.5", false], ["LGA275.jpg", "LG A275 Black Unlocked GSM Dual SIM QuadBand Cell Phone - International Version - No Warranty", "LG", "79.89", "4", "3G", "3.5", false], ["BLUBlue.jpg", "BLU Dash JR W D141w Unlocked GSM Dual-SIM Android Cell Phone - Blue", "BLU", "59.99", "4", "GSM", "4", false], ["LGVN250.jpg", "LG Cosmos VN250 Verizon Phone (POST PAID)", "LG", "449.99", "64", "4G", "3.5", false], ["LGOptimus.jpg", "LG Optimus Dynamic Android Prepaid Phone with Triple Minutes (Tracfone)", "LG", "29.99", "16", "GSM", "4", true], ["LG305c.jpg", "Tracfone LG 305C with Triple Minutes for Life (Tracfone)", "LG", "99.99", "16", "3G", "4", false], ["SamsungC3520.jpg", "Samsung GT-C3520I Unlocked Quad-Band GSM Phone with 1.3 MP Camera, MP3 Player...", "Samsung", "64.99", "8", "3G", "3.5", false], ["LGVN251.jpg", "LG VN251 VN 251 COSMOS 2 Verizon Wireless Slider Keyboard Bluetooth Cell Phone", "LG", "58.69", "16", "4G", "4", false], ["ZTEUSAZ222.jpg", "AT&T Z222 Go Phone (AT&T)", "ZTE USA", "24.85", "4", "4G", "4", false], ["BLUQ170T.jpg", "BLU Q170T Samba TV Unlocked Dual SIM Quad-Band GSM Phone (Black/Red)", "BLU", "26.08", "32", "3G", "3.5", true], ["Apple4SWhite.jpg", "Apple iPhone 4S GSM Unlocked 16GB Smartphone - White", "Apple", "199.99", "16", "GSM", "4", false], ["LG840G.jpg", "LG 840G Prepaid Phone With Triple Minutes (Tracfone)", "LG", "48.95", "32", "4G", "3.5", false], ["SamsungA157V.jpg", "Samsung a157V (AT&T)", "Samsung", "14.99", "8", "3G", "3.5", false], ["LGVN150.jpg", "LG Revere VN150 Bluetooth CDMA Camera Flip Cell Phone Verizon or PagePlus", "LG", "72.50", "2", "GSM", "3.5", false], ["NOKIA106.jpg", "Nokia 106 Unlocked GSM Dual-Band Cell Phone w/ SMS and FM Radio - Black", "Nokia", "17.99", "2", "GSM", "4", false], ["ZTEZ222.jpg", "Unlocked ZTE Z222 Flip Phone With Camera For ATT, T-Mobile and Other Supported GSM Networks...", "ZTE", "27.79", "16", "4G", "3.5", false], ["Apple4SUnlocked.jpg", "Apple iPhone 4S 16GB 3G WiFi Black Smartphone Unlocked", "Apple", "182.99", "16", "3G", "4", false], ["BLUQ170TBlue.jpg", "BLU Q170T Samba TV Unlocked Dual SIM Quad-Band GSM Phone (Black/Blue)", "BLU", "22.99", "2", "GSM", "4", false], ["SamsungC3520Gray.jpg", "Samsung GT-C3520BLK Unlocked GSM Cell Phone,Charcoal Gray", "Samsung", "99.99", "8", "3G", "3.5", false], ["LG306G.jpg", "LG 306G 3G Cell Phone | TracFone", "TracFone", "4.99", "2", "GSM", "3.5", false]]; var path = (location.origin + location.pathname); var srcBase = "$DEMOROOT$/spread/source/"; // if (path.indexOf("#") === -1) { // // srcBase = location.origin + location.pathname; // if (path.indexOf("demos/") > -1) { // srcBase = path.substr(0, path.indexOf("demos/")); // } // } window.onload = function () { var dataSource = new GC.Spread.Slicers.GeneralSlicerData(datas, dataNames); var brandSlicer = new AmazonSlicer(document.getElementById('slicer_Brand')); brandSlicer.setData(dataSource, "Brand"); var memorySlicer = new AmazonSlicer(document.getElementById('slicer_Memory')); memorySlicer.setData(dataSource, "Internal Memory"); var netWorkSlicer = new AmazonSlicer(document.getElementById('slicer_Network')); netWorkSlicer.setData(dataSource, "Network"); var customerReviewSlicer = new AmazonSlicer(document.getElementById('slicer_CustomerReview')); customerReviewSlicer.setData(dataSource, "Avg. Customer Review"); }; function AmazonSlicer(container) { this.container = container; } AmazonSlicer.prototype.constructor = AmazonSlicer; AmazonSlicer.prototype.setData = function (slicerData, columnName) { this.slicerData = slicerData; this.columnName = columnName; this.data = slicerData.getData(columnName); this.exclusiveDatas = slicerData.getExclusiveData(columnName); this.slicerData.attachListener(this); this.onDataLoaded(); } AmazonSlicer.prototype.onDataLoaded = function () { let slicer = this; var header = '<div class="slicerHeader">' + '<div class="slicerHeaderBorder"></div>' + '<span style="font-size:medium">' + this.columnName + '</span>' + '<div class="slicerHeaderBorder"></div>' + '</div>'; if (slicer.container.className.indexOf('slicer') < 0) { slicer.container.className = slicer.container.className + ' slicer'; } var datas = slicer.exclusiveDatas; let slicerContent = header; if (slicer.columnName === "Avg. Customer Review") { for (var i = 0; i < datas.length; i++) { var count = 0; for (var j = 0; j < datas.length; j++) { if (parseFloat(datas[j]) >= parseFloat(datas[i])) { count += slicer.slicerData.getRowIndexes(slicer.columnName, slicer.slicerData.getExclusiveData(slicer.columnName).indexOf(datas[j])).length; } } var imageSrcPrefix = srcBase ? srcBase : ''; var image = '<img src="' + imageSrcPrefix + 'images\/' + datas[i] + '.png" alt="' + datas[i] + '"style="vertical-align:middle"></img><span>& Up</span>' slicerContent += '<div>' + image + '<span style="color:#A29999">(' + count + ')</span></div>'; } } else { for (var i = 0; i < datas.length; i++) { var count = slicer.slicerData.getRowIndexes(slicer.columnName, slicer.slicerData.getExclusiveData(slicer.columnName).indexOf(datas[i])).length; // todo label include checkbox slicerContent += '<label style="display: block">' + '<input type="checkbox"/><span>' + datas[i] + '</span><span style="color:#A29999">(' + count + ')</span>' + '</label>'; } } slicer.container.innerHTML = slicerContent; var headerEle = slicer.container.firstChild; headerEle.onmousedown = function (e) { slicer.slicerData.doUnfilter(slicer.columnName); if (slicer.columnName !== "Avg. Customer Review") { var childNodes = slicer.container.childNodes; for (var i = 1, length = childNodes.length; i < length; i++) { childNodes[i].childNodes[0].checked = false; } } } var items = []; var children = slicer.container.childNodes children.forEach((item, index) => { if (index === 0) { return; } items.push(item); item.className = item.className + ' slicerItem'; item.onmouseenter = function (e) { e.target.className += ' hover'; } item.onmouseleave = function (e) { e.target.className = e.target.className.replace('hover', '').trim(); } if (slicer.columnName === "Avg. Customer Review") { item.onclick = function (e) { var exclusiveData = slicer.slicerData.getExclusiveData(slicer.columnName), childNodes = this.parentNode.childNodes, indexes = []; var currentAlt = item.childNodes[0].alt; for (var i = 1, length = childNodes.length; i < length; i++) { var tempAlt = childNodes[i].childNodes[0].alt; if (parseFloat(tempAlt) >= parseFloat(currentAlt)) { indexes.push(exclusiveData.indexOf(tempAlt)); } } if (indexes.length === 0) { slicer.slicerData.doUnfilter(slicer.columnName); } else { slicer.slicerData.doFilter(slicer.columnName, {exclusiveRowIndexes: indexes}) } } } else { // label checkbox item.onclick = function (e) { var exclusiveData = slicer.slicerData.getExclusiveData(slicer.columnName), childNodes = item.parentNode.childNodes, indexes = []; for (var i = 1, length = childNodes.length; i < length; i++) { if (childNodes[i].childNodes[0].checked) { indexes.push(exclusiveData.indexOf(childNodes[i].childNodes[1].innerText)) } } if (indexes.length === 0) { slicer.slicerData.doUnfilter(slicer.columnName); } else { slicer.slicerData.doFilter(slicer.columnName, {exclusiveRowIndexes: indexes}) } } } }); slicer.items = items; slicer.onFiltered(null); }; AmazonSlicer.prototype.resetClass = function () { var items = this.items; var classes = ["filtered", "partial", "filteredOutBySelf", "filteredOutByOther"]; for (var i = 0; i < items.length; i++) { for (var k = 0; k < classes.length; k++) { items[i].className = items[i].className.replace(classes[k], '').trim(); } } }; AmazonSlicer.prototype.onFiltered = function () { this.resetClass(); var items = this.items; var filteredItems = this.slicerData.getFilteredIndexes(this.columnName); for (var i = 0; i < filteredItems.length; i++) { if (items[filteredItems[i]].className.indexOf('filtered') < 0) { items[filteredItems[i]].className = items[filteredItems[i]].className + ' filtered'; } } var filteredOutItems = this.slicerData.getFilteredOutIndexes(this.columnName, GC.Spread.Slicers.FilteredOutDataType.byCurrentColumn); for (var i = 0; i < filteredOutItems.length; i++) { if (items[filteredOutItems[i]].className.indexOf('filteredOutBySelf').indexOf < 0) { items[filteredOutItems[i]].className = items[filteredOutItems[i]].className + ' filteredOutBySelf' } } var filteredOutByOtherItems = this.slicerData.getFilteredOutIndexes(this.columnName, GC.Spread.Slicers.FilteredOutDataType.byOtherColumns); for (var i = 0; i < filteredOutByOtherItems.length; i++) { if (items[filteredOutByOtherItems[i]].className.indexOf('filteredOutByOther') < 0) { items[filteredOutByOtherItems[i]].className = items[filteredOutByOtherItems[i]].className + 'filteredOutByOther' } } this.refreshList(); }; AmazonSlicer.prototype.refreshList = function () { var list = document.getElementById('ss'); var indexes = this.slicerData.getFilteredRowIndexes(); let listItemsHtml = ''; for (var i = 0, rowCount = indexes.length; i < rowCount; i++) { var imageSrcPrefix = srcBase ? srcBase : ''; var image1 = '<div class="p_image"><img src="' + imageSrcPrefix + 'images\/' + datas[indexes[i]][0] + '" style="width:160px;height:160px"></img></div>'; var image2 = '<div class="p_vote"><img src="' + imageSrcPrefix + 'images\/' + datas[indexes[i]][6] + '.png"/></div>'; listItemsHtml += '<div style="width:200px;margin-left:20px;margin-top:10px;display:inline-block" >' + image1 + '<div class="p_description" style="height:86px;font-size:medium;color:#0066C0">' + datas[indexes[i]][1] + '</div>' + '<div class="p_company">by ' + datas[indexes[i]][2] + '</div>' + '<div class="p_price" style="font-weight:bold;color:#B52704">$' + datas[indexes[i]][3] + '</div>' + image2 + '</div>' } list.innerHTML = listItemsHtml; }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta name="spreadjs culture" content="ja-jp" /> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/ja/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/ja/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/ja/purejs/node_modules/@mescius/spread-sheets-resources-ja/dist/gc.spread.sheets.resources.ja.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"></div> <!--<div class="sample-options layout_slicer">--> <div class="options-container"> <p class="desc">以下の各オプションを使用して、店舗の表示結果をフィルタリングします。</p> <div id="slicer_Brand" class="slicer"></div> <div id="slicer_Memory" class="slicer"></div> <div id="slicer_Network" class="slicer"></div> <div id="slicer_CustomerReview" class="slicer"></div> </div> <!--</div>--> </div> </body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: auto; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 10px; } .slicer { margin-bottom: 10px; } .slicerHeader { position: relative; padding-top: 1px; font-weight: 600; } .hover { color: #E47911; cursor: default; } .desc { padding: 2px 10px; margin-top: 0; background-color: #F4F8EB; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }