Skip to content

Instantly share code, notes, and snippets.

@willhlaw
Forked from anonymous/index.html
Last active April 14, 2017 20:11
Show Gist options
  • Save willhlaw/1a362f6b88f2ea98133f16c41195a2b9 to your computer and use it in GitHub Desktop.
Save willhlaw/1a362f6b88f2ea98133f16c41195a2b9 to your computer and use it in GitHub Desktop.
smooth div scroll 4 -trying straight forward approach
<!-- HTML below from below from http://www.smoothdivscroll.com/runningTicker.html but took out the display: none styles for the hotspots (but they are still not appearing) -->
<div id="ticker">
<div class="ticker-container">
<div id="scrollingText">
<div id="ticker-left" class="arrow">
</div>
<div class="scrollWrapper">
<div id="scrollableArea" class="container-fluid scrollableArea">
<ul class="row" id="records">
<!-- XML Feed Imported here
Sample records below will be replaced by XML records and
are only included to help with look and feel while
developing (the XML parsing).
-->
<!-- <li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.350%</span><span class="indicator">↑</span></div>
</li>
<li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.351%</span><span class="indicator">↑</span></div>
</li>
<li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.352%</span><span class="indicator">↑</span></div>
</li>
<li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.353%</span><span class="indicator">↑</span></div>
</li>
<li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.354%</span><span class="indicator">↑</span></div>
</li>
<li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.355%</span><span class="indicator">↑</span></div>
</li>
<li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.356%</span><span class="indicator">↑</span></div>
</li>
<li class="record"><span class="name">10 Year Swap</span>
<div><span class="change">2.357%</span><span class="indicator">↑</span></div>
</li> -->
</ul>
<!-- Need to include jquery before $(document).ready call since listing
JavaScript dependencies in codepen cause them to be appended to html body
which happens below the script and too late so browser chokes
because it would not recognize $ yet -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
// Configurable variable listed here at the top
// Url of XML Feed from JBL site
var xmlUrl = 'https://www.thefinancials.com/syndicated/JBLEVYCO/feed.xml';
// Selector text for the element that will host the XML data records
var recordsElemSelector = '#records';
// Selector text of the element that will have the scrolling behavior
// attached to it. It may or may not be same as recordsElemSelector
// depending on scrolling plugin, left and right arrows and wrapper divs
var scrollingElemSelector = '#scrollableArea';
// Array of fields from XML data records that we want to extract
// (order doesn't matter)
var fieldNames = ['date', 'name', 'symbol', 'last', 'change',
// These are calculated fields.
// lastAsPercent is 'last' turned into a percent to 2 decimal places
// changeDirectionClass is either 'change-up', 'change-none',
// or 'change-down' and changeDirection is either '↑', '', or '↓'
'lastAsPercent', 'changeDirectionClass', 'changeDirection'];
// Convert fieldNames to an mapped object with a bracketted integer to
// use for replacing with the real value in the recordTemplate.
// It ends up creating an object that looks like:
// {date: '{0}', dateIndex: 0, name: '{1}', nameIndex: 1,...}
// so that "fields.name" can be written in a template and formatted
// (see String.prototype.format) instead of needing to remember
// (or update the integer if fields change in the future) that name
// is "{1}". See, I told you order doesn't matter.
// You are not going to be configuring this one, but it needs to be
// before the recordTemplate and it's purpose is to make life easier
// by allowing you to control how XML ends up being rendered.
var fields = fieldNames.reduce(function (acc, value, index) {
acc[value] = '{' + index + '}';
acc[value + 'Index'] = index;
return acc;
}, {});
// Template for the XML records that gets replaced into recordsElem
var recordTemplate =
"<li class='col-xs-12 col-sm-6 col-md-4 col-lg-3 record'>" +
"<span class='name'>" +
fields.name +
"</span>" +
"<div>" +
"<span class='change " + fields.changeDirectionClass + "'>" +
fields.lastAsPercent +
"<span class='change-symbol'>" +
fields.changeDirection
"</span>" +
"</span>" +
"</div> " +
"</li>";
// Helper utility formats string 'Hello {0}{1}'.format(['Bob', '!']) into 'Hello Bob!'
// Or in this ticker record case, here's a simple example:
// '<li>{1}: {4}</li>'.format(
// ['3/29/2017', '5 Year Treasury Yield', 'TREASURY Y5', '0.01929', '-2.27%']);
// results in:
// '<li>5 Year Treasury Yield: -2.27%</div>'
String.prototype.format = function () {
var args = arguments;
return this.replace(/\{(\d+)\}/g, function (m, n) { return args[0][n]; });
};
$(document).ready(function() {
loadXml(xmlUrl, parseXmlAndUpdateRecords, handleXmlError);
});
function loadXml(url, onSuccess, onError) {
$.ajax({
type: "GET",
url: url,
dataType: "xml",
success: onSuccess,
error: onError
});
}
function handleXmlError(requestObj, statusStr, errorStr) {
var couldNotLoadXmlMessage = ''; // Let's just leave ticker blank
// Write the error details to the browser's console
console.error('Cannot load the XML:', statusStr, errorStr);
// Update the page with a message (or leave blank / hide)
$(recordsElemSelector).html(couldNotLoadXmlMessage);
}
function parseXmlAndUpdateRecords(xmlData, statusStr, requestObj) {
// Get record of <li> DOM elements, append to existing recordsElem, and make it scrollable
var recordElems = $(xmlData).find('record').map(function (idx, record) {
var $record, recordArray, recordString, recordDomElem;
// We are going to get fields out of the record and put them into a template
// and return it as a <li> DOM element
// Turn record node into a jQuery object
$record = $(record);
// Create array of [<date>, <name>, ..., <change>] values;
recordArray = fieldNames.map(getValue);
// Replace calculated field's '' with proper values
recordArray = setCalculatedFields(recordArray);
// Replace tokens like {name} in template with
// <actual-value-of-name> from array
recordString = recordTemplate.format(recordArray);
// Turn string into a DOM element
recordDomElem = $.parseHTML(recordString);
return recordDomElem;
// Helper function to pull a field as text out of the record
function getValue (fieldName) {
return $record.find(fieldName).text();
}
function setCalculatedFields(recordArray) {
// A few extra fields need to be calculated so they can
// be used in the record template to be rendered.
var lastAsPercent;
var changeAsFloat, changeDirectionClass, changeDirection;
lastAsPercent = roundToMoney(getValue('last') * 100) + '%';
recordArray[fields.lastAsPercentIndex] = lastAsPercent;
changeAsFloat = parseFloat(getValue('change'));
if (changeAsFloat < 0) {
changeDirectionClass = 'change-down';
changeDirection = '↓';
} else if (changeAsFloat > 0) {
changeDirectionClass = 'change-up';
changeDirection = '↑';
} else {
changeDirectionClass = 'change-none';
changeDirection = '';
}
recordArray[fields.changeDirectionClassIndex] =
changeDirectionClass;
recordArray[fields.changeDirectionIndex] = changeDirection;
return recordArray;
}
function roundToMoney(number) {
// Rounds a float number to 2 decimal places
// Rounding floats in JavaScript is messy, thus the
// rounding using a scaling technique
// See mrkschan's comment on
// http://stackoverflow.com/a/11832950/7680642
var ensureNumber = parseFloat(number);
var roundToAtMostTwoDecimals = Math.round(
(ensureNumber + 0.00001) * 100) / 100
var ensureTwoDecimals = roundToAtMostTwoDecimals.toFixed(2);
return ensureTwoDecimals;
}
});
// Replace the page's recordsElem with the array of record DOM elements
$(recordsElemSelector).html(recordElems);
// Make these records scrollable
makeScrollable($(scrollingElemSelector));
}
// Below code was copied from old
// jblevy.com site and heavily customized.
// 'elemToScroll' parameter is not yet used
// since code makes multiple reuse of '#records'
// and don't want to change any of it yet
function makeScrollable(elemToScroll) {
var $scrollableContainer = $(elemToScroll);
var marginSpace = parseInt($('.record').first().css('margin-right'));
var $partialRecord;
// Percent Forgiveness is multiplied against a record's width to determine the
// amount that a record can be off the screen but still
// be considered a "full record" and not a "partially visible record".
var partialRecordPercentForgiveness = .3;
function adjustWidthClasses() {
// Iterate through each record and
// add classes to the ".name" elements
// according to if record is extra wide "tighten"
// or extra skinny "widen"
$('.record').each(function (idx, record) {
$record = $(record);
var $name = $record.find('.name');
var recordLeft = $record.offset().left;
// recordWidth is no longer dynamic now that bootstrap columns
// have been implemented, so use length of text
//var recordWidth = $record.width();
var recordTextLength = ($record.text() || '').length;
var shortLength = 17 // "SWAP" records will be short and .widen class added
var longLength = 25; // "Treasury" records will be long and .tighten class added
if (recordTextLength >= longLength) {
$name.addClass('tighten');
} else if (recordTextLength <= shortLength) {
$name.addClass('widen');
}
});
}
adjustWidthClasses();
function findPartialAndHiddenRecords(callback) {
// Finds any record that is partially off or entirely off screen
// and calls the callback function to work on each record
// Returns first partially/hidden record found
var containerLeft = $scrollableContainer.offset().left;
var containerRightEdge = containerLeft + $scrollableContainer.width();
var $firstPartialRecord;
$('.record').each(function (idx, record) {
$record = $(record);
var recordLeft = $record.offset().left;
var recordWidth = $record.width();
var recordRightEdge = recordLeft + recordWidth
- (recordWidth * partialRecordPercentForgiveness);
if (recordRightEdge > containerRightEdge) {
callback($record);
if (!$firstPartialRecord) {
$firstPartialRecord = $record;
}
}
});
return $firstPartialRecord;
}
function findVisibleRecords(callback) {
// Finds any record that is visible on screen
// and calls the callback function to work on each record
var containerLeft = $scrollableContainer.offset().left;
var containerRightEdge = containerLeft + $scrollableContainer.width();
$('.record').each(function (idx, record) {
$record = $(record);
var recordLeft = $record.offset().left;
var recordWidth = $record.width();
var recordRightEdge = recordLeft + recordWidth;
if (recordRightEdge <= containerRightEdge) {
callback($record);
}
});
}
function hidePartialAndHiddenRecords() {
var firstPartialRecord = findPartialAndHiddenRecords(function ($record) {
//$record.css('visibility', 'hidden');
$record.switchClass('', 'partial');
});
return firstPartialRecord;
}
function showVisibleRecords() {
findVisibleRecords(function ($record) {
//$record.css('visibility', 'visible');
$record.switchClass('partial');
});
}
function showPartialRecord($outofviewRecord) {
//$outofviewRecord.css('visibility', 'visible');
if ($outofviewRecord && switchClass in $outofviewRecord) {
$outofviewRecord.switchClass('partial');
}
}
$partialRecord = hidePartialAndHiddenRecords();
function tickerLeft() {
var recordWidth = $('.record').last().css('width');
recordWidth = Math.round(parseInt(recordWidth)) + marginSpace;
// Bring last record into front and shift left so it smoothly
// comes into view. This does not need to happen in tickerRight
// because the records are offscreen ready to animate in.
$('ul#records').css({ 'left' : -recordWidth + 'px' });
$('#records').prepend($('.record').last());
showVisibleRecords();
$('ul#records').animate({ 'left' : (0 + "px") }, 750, function() {
$partialRecord = hidePartialAndHiddenRecords();
// Ensure that all records on screen are visible
showVisibleRecords();
if (control == true) {
$('#ticker-left').one('click',function(e) {
tickerLeft();
});
}
});
}
function tickerRight() {
var recordWidth = $('.record').first().css('width');
recordWidth = Math.round(parseInt(recordWidth)) + marginSpace;
showPartialRecord($partialRecord);
console.log('ticker right');
$('ul#records').animate({ 'left' : (-recordWidth + "px") }, 750, function() {
console.log('ticker right, moving records left');
$partialRecord = hidePartialAndHiddenRecords();
// Ensure that all records on screen are visible
showVisibleRecords();
$('#records').append($('.record').first());
$('ul#records').css({ 'left' : 0 + 'px' });
if (control == true) {
$('#ticker-right').one('click',function(e) {
tickerRight();
});
}
});
}
/* Ticker auto advances until user takes control */
function autoAdvance() {
if (control == false) {
tickerRight();
}
}
if ($('#ticker').length > 0) {
control = false;
var autoTicker = setInterval(function() { autoAdvance(); }, 5000);
}
$('#ticker').hover(function() {
control = true;
}, function() {
control = false;
});
/* Attach Ticker control events */
$('#ticker-left').one('click',function(e) {
tickerLeft();
});
$('#ticker-right').one('click',function(e) {
tickerRight();
});
}
</script>
</div>
</div>
<div id="ticker-right" class="arrow">>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js"></script>
<script src="https://cdn.rawgit.com/entozoon/Smooth-Div-Scroll/d64ef164a00e6a92fa87043b1b1e923ff077ee46/js/jquery.smoothdivscroll-1.3-min.js"></script>
<script src="https://cdn.rawgit.com/davetayls/jquery.kinetic/master/jquery.kinetic.min.js"></script>
.ticker-container {
font-size: 18px;
}
/* From: http://www.jblevyco.com/
Financial Records Ticker */
#ticker {
/*width: 826px;*/
text-align: center;
margin: 30px auto 0 auto;
padding: 35px 25px;
clear: both;
overflow: hidden;
/* font-family copied from page's
computed font-family */
font-family: "arno-pro", Georgia, Times, serif;
}
#ticker {
margin:30px auto 0 auto;
padding: 35px 25px;
clear: both;
overflow: hidden;
/* font-family copied from page's
computed font-family */
font-family: "arno-pro", Georgia, Times, serif;
}
#ticker .arrow {
width: 14px;
height: 17px;
position: absolute;
/* Change from 1000 to 1 so that mouseover
actually speeds up scroll */
z-index: 1;
padding: 15px 10px;
background: #16395C;
display: block;
}
#ticker .arrow a {
color: #FFFFFF;
text-decoration: none;
}
#ticker-left {
left: 0px;
top: 0px;
}
#ticker-right {
right: 0px;
top: 0px;
}
#ticker #records {
list-style-type: none;
position: absolute;
/* Changing 'left' may need to coincide
with changes in animate script */
left: -0px;
width: 1722px;
}
#ticker li.record {
float: left;
color: #333333;
margin-right: 20px;
}
#ticker li.record.partial {
opacity:0.5
}
#ticker span.name {
font-weight: 300;
float: left;
padding: 5px;
}
#ticker span.name.tighten {
letter-spacing: -1.5px;
}
#ticker span.name.widen {
letter-spacing: 1.1px;
}
#ticker li.record div {
background: #4C6582;
border-radius: 3px;
text-align: center;
float: right;
margin: -2px 0 0 0;
padding: 5px;
}
#ticker span.change {
font-size: 15px;
color: #FFFFFF;
}
#ticker span.indicator {
font-size: 13px;
margin: 0 0 0 2px;
}
/* CSS below from http://www.smoothdivscroll.com/runningTicker.html
*/
#scrollingText
{
width: 100%;
height: 34px;
position: relative;
padding: 2px 0px;
}
/* Changed p to * in this css rule to account
for xml feed code using both div and p */
#scrollingText div.scrollableArea *
{
/*
display: block;
float: left;
margin: 0;
padding-right: 7px;
padding-top: 1px;
*/
white-space: nowrap;
}
/* CSS below pasted from http://smoothdivscroll.com/css.html
since the smoothDivScroll.css referenced by the smoothDivScroll library is http:// and codepen complains and updated to replace relative references just to get it to work in this codepen.
To use for client side, recommend copying
the files over to Wordpress.
*/
/* You can alter this CSS in order to give Smooth Div Scroll your own look'n'feel */
/* Invisible left hotspot */
div.scrollingHotSpotLeft
{
/* The hotspots have a minimum width of 100 pixels and if there is room the will grow
and occupy 15% of the scrollable area (30% combined). Adjust it to your own taste. */
min-width: 75px;
width: 10%;
height: 100%;
/* There is a big background image and it's used to solve some problems I experienced
in Internet Explorer 6. */
background-image: url(http://www.smoothdivscroll.com/images/big_transparent.gif);
background-repeat: repeat;
background-position: center center;
position: absolute;
z-index: 200;
left: 0;
/* The first url is for Firefox and other browsers, the second is for Internet Explorer */
cursor: url(http://www.smoothdivscroll.com/images/cursors/cursor_arrow_left.png), url(http://www.smoothdivscroll.com/images/cursors/cursor_arrow_left.cur),w-resize;
}
/* Visible left hotspot */
div.scrollingHotSpotLeftVisible
{
background-image: url(http://www.smoothdivscroll.com/images/arrow_left.gif);
background-color: #fff;
background-repeat: no-repeat;
opacity: 0.35; /* Standard CSS3 opacity setting */
-moz-opacity: 0.35; /* Opacity for really old versions of Mozilla Firefox (0.9 or older) */
filter: alpha(opacity = 35); /* Opacity for Internet Explorer. */
zoom: 1; /* Trigger "hasLayout" in Internet Explorer 6 or older versions */
}
/* Invisible right hotspot */
div.scrollingHotSpotRight
{
min-width: 75px;
width: 10%;
height: 100%;
background-image: url(http://www.smoothdivscroll.com/images/big_transparent.gif);
background-repeat: repeat;
background-position: center center;
position: absolute;
z-index: 200;
right: 0;
cursor: url(http://www.smoothdivscroll.com/images/cursors/cursor_arrow_right.png), url(http://www.smoothdivscroll.com/images/cursors/cursor_arrow_right.cur),e-resize;
}
/* Visible right hotspot */
div.scrollingHotSpotRightVisible
{
background-image: url(http://www.smoothdivscroll.com/images/arrow_right.gif);
background-color: #fff;
background-repeat: no-repeat;
opacity: 0.35;
filter: alpha(opacity = 35);
-moz-opacity: 0.35;
zoom: 1;
}
/* The scroll wrapper is always the same width and height as the containing element (div).
Overflow is hidden because you don't want to show all of the scrollable area.
*/
div.scrollWrapper
{
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
}
div.scrollableArea
{
position: relative;
width: auto;
height: 100%;
}
/* MMD ADDITIONS */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment