T
We're Happier Together! NYC Devshop has joined the HappyFunCorp family! Learn more!

Devshop

Dynamic Styles Made Easy in Rails

Dynamic Styles Made Easy in Rails

Development

Dynamic Styles Made Easy in Rails

Posted by: Jared Rader

Monday, Jul 7th, 2014

While I definitely consider myself more of a backend developer, I've been lucky that my job pushes me to get more comfortable with front-end implementation. I learned a pretty neat and simple trick the other day for dynamic data visualization that I felt was worth sharing.

Our latest project, Daily Poll, sends users - you guessed it - a daily poll via text message. The questions, for now, are yes/no questions, and we were tasked with displaying the results on the homepage as a colorful bar chart.

We need the heights of each chart to be representative of the percentage of votes. How could one get this to be dynamic?

One way to accomplish this is with inline styling. Inline styling is generally frowned upon, but it makes this really easy.

.yes-section-container

.yes-people-box
.yes-people
%h2 YES!
= image_tag("cheering_blue.png")
.yes-graph
.yes-box{:style => "height: #{box_height(poll.yes_count,
poll.votes.count)}px;"}
%span= number_to_percentage(poll.yes_percent, precision: 0)
.no-section-container
.no-people-box
.no-people
%h2 NO!
= image_tag("cheering_red.png")
.no-graph
.no-box{:style => "height: #{box_height(poll.no_count,
poll.votes.count)}px;"}
%span= number_to_percentage(poll.no_percent, precision: 0)

You'll notice inside the inline styling for the yes and no boxes, we call a helper method box_height, which handles generating the heights we need. We pass poll.yes_count or poll.no_count (methods we've defined in the Poll model) along with the total number of votes.

In box_height, we need to determine what our maximum height can be. Once we have that, we can multiply that by the number of total yes/no votes, dividing the product by the total number of votes:

def box_height(yes_no_votes, total_votes)

if total_votes < 1
return 0
else
380 * yes_no_votes / total_votes
end
end

What's going on in this method? If no vote records exist for the poll, we just return 0, giving the chart a height of zero. Otherwise, we multiply 380 (the max height for our charts) by the number of yes or no records, divided by the total number of vote records. Thus, if we have 52 yes votes out of 100, we get a height of 197px, or 52% of our max height. Perfect!

Spice it up with jQuery
We wanted to implement a cool effect where the polls would sprout up from nothing to their appropriate heights as you scrolled to that section of the page. With jQuery, this isn't too difficult to accomplish.

I hadn't worked with any scrolling effects before, so I did a quick Google search and popped open the jQuery docs and a few StackOverflow posts on the subject. I came across a simple solution for determining whether an element is scrolled into view. I define this function above the $(document).ready() {} declaration:

function isScrolledIntoView(elem) {

var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= docViewBottom));
}

Using jQuery's .offset() and .height() functions, I determine how far from the top is an element on the page, returning true or false if the bottom of the element is less than or equal to the height of the window plus how far it is from the top of the window. That may sound confusing - it took a few minutes for me to wrap my head around it - but after playing around in the Chrome console, I got it. So I'd encourage you to do the same until the first sentence of this paragraph makes sense.

Now that I have a function that tells me whether a certain element is in view, I can work some real jQuery magic. If the element is in view, I can use jQuery's .slideDown() method to make the bars sprout into view:

$(window).scroll(function() {

if (isScrolledIntoView($('.question-header'))) {
$('.yes-box').slideDown(1000);
$('.no-box').slideDown(1000);
} else {
$('.yes-box').slideUp(10);
$('.no-box').slideUp(10);
}
});

I suppose the .slideDown() method is called that because jQuery's creators decided that most elements would be sliding into view from top to bottom, but it still achieves the desired effect if you've got something going from bottom to top. It may seem a little counterintuitive at first, but it works!

Devshop

About Us

Devshop is a highly motivated group of entrepreneurs, developers, and designers that aim to work with companies that are looking for an edge. Each member of our team brings something unique to the table allowing us to cater our services specifically to meet your needs and exceed your expectations.