I have this code from an old website. I want to initialize this function in my custom js file. But I can't understand how to call this function in my custom.js file. Actually, This code performs as like as a scrollable slider which behaves that when I scroll to down than previous & next scroll step will be opacity 0 and current step opacity will be 1.
(window.webpackJsonpOdmans = window.webpackJsonpOdmans || []).push([
[64], {
433: function(t, e, i) {},
435: function(t, e, i) {
var n = {
"./oddmans-cross-grey.svg": 436,
"./global-scroll.svg": 437
};
function s(t) {
var e = o(t);
return i(e)
}
function o(t) {
var e = n[t];
if (!(e + 1)) {
var i = new Error("Cannot find module '" + t + "'");
throw i.code = "MODULE_NOT_FOUND", i
}
return e
}
s.keys = function() {
return Object.keys(n)
}, s.resolve = o, t.exports = s, s.id = 435
},
436: function(t, e, i) {
"use strict";
i.r(e), e.default = {
id: "icon-oddmans-cross-grey-usage",
viewBox: "33 -33 88 88",
url: i.p + "scroll-steps.svg#icon-oddmans-cross-grey",
toString: function() {
return this.url
}
}
},
437: function(t, e, i) {
"use strict";
i.r(e), e.default = {
id: "icon-global-scroll-usage",
viewBox: "0 0 14 22",
url: i.p + "scroll-steps.svg#icon-global-scroll",
toString: function() {
return this.url
}
}
},
482: function(t, e, i) {
"use strict";
i.r(e), i(16), i(11), i(12), i(433);
var n = i(1),
s = (i(28), i(34), i(35), i(36), i(5), i(6), i(29), i(3), i(8), i(9), i(10), i(0)),
o = i(4),
r = i.n(o),
a = i(2);
function l(t) {
return (l = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) {
return typeof t
} : function(t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
})(t)
}
function h(t) {
return (h = Object.setPrototypeOf ? Object.getPrototypeOf : function(t) {
return t.__proto__ || Object.getPrototypeOf(t)
})(t)
}
function u(t, e) {
return (u = Object.setPrototypeOf || function(t, e) {
return t.__proto__ = e, t
})(t, e)
}
function c(t) {
if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
return t
}
var d = function(t) {
function e() {
var t, i, n;
! function(t, i) {
if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
}(this);
for (var s = arguments.length, o = new Array(s), r = 0; r < s; r++) o[r] = arguments[r];
return (i = !(n = (t = h(e)).call.apply(t, [this].concat(o))) || "object" !== l(n) && "function" != typeof n ? c(this) : n).setBinds = i.setBinds.bind(c(c(i))), a.f.isTouch && !a.f.deviceTypeByViewport !== a.c ? i.onTouchDetect() : (i.setBinds(), i.initContent()), i
}
var i;
return function(t, e) {
if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
t.prototype = Object.create(e && e.prototype, {
constructor: {
value: t,
writable: !0,
configurable: !0
}
}), e && u(t, e)
}(e, s.a), (i = [{
key: "setBinds",
value: function() {
this.showNextStep = this.showNextStep.bind(this), this.initContent = this.initContent.bind(this), this.onScroll = this.onScroll.bind(this), this.setIndex = this.setIndex.bind(this), this.change = this.change.bind(this), this.setHiddens = this.setHiddens.bind(this), this.addListeners = this.addListeners.bind(this), this.goScroll = this.goScroll.bind(this)
}
}, {
key: "onTouchDetect",
value: function() {
this.element.classList.add("scroll-steps--second-style")
}
}, {
key: "initContent",
value: function() {
this.steps = this.refs.steps, this.btn = this.refs.btn, this.cross = this.refs.cross, this.scrollIcon = this.refs.scrollIcon, this.toDown = !0, this.blockEvent = !1, this.duration = 600, this.index = 0, this.height = this.element.getBoundingClientRect().height;
for (var t = 0; t < this.steps.length; t++) this.steps[t].style.visibility = "hidden", this.steps[t].style.opacity = 0, this.steps[t].hiddenElements = function(t) {
if (Array.isArray(t)) {
for (var e = 0, i = new Array(t.length); e < t.length; e++) i[e] = t[e];
return i
}
}(e = this.steps[t].querySelectorAll(".hidden")) || function(t) {
if (Symbol.iterator in Object(t) || "[object Arguments]" === Object.prototype.toString.call(t)) return Array.from(t)
}(e) || function() {
throw new TypeError("Invalid attempt to spread non-iterable instance")
}(), this.steps[t].header = this.steps[t].querySelector(".scroll-steps__title");
var e;
this.setIndex(), this.currentStep.style.visibility = "", this.currentStep.style.opacity = 1, this.setHiddens(this.currentStep, "remove"), this.addListeners()
}
}, {
key: "addListeners",
value: function() {
var t = this;
this.btn.addEventListener("click", function() {
t.toDown = !0, t.goScroll(t.height)
}), document.body.addEventListener("wheel", this.onScroll)
}
}, {
key: "goScroll",
value: function(t) {
r()({
targets: "body, html",
duration: 500,
scrollTop: t,
easing: "easeInOutQuart"
})
}
}, {
key: "setHiddens",
value: function(t, e) {
for (var i = 0; i < t.hiddenElements.length; i++) t.hiddenElements[i].classList[e]("hidden")
}
}, {
key: "onScroll",
value: function(t) {
this.blockEvent && t.preventDefault();
var e = window.pageYOffset < .6 * this.height;
if (!this.blockEvent && e) {
var i = t.deltaY;
i > 0 && this.nextStep ? (t.preventDefault(), this.toDown = !0, this.change()) : i < 0 && this.previousStep && (t.preventDefault(), this.toDown = !1, window.pageYOffset > 0 && e && this.goScroll(0), this.change())
}
}
}, {
key: "change",
value: function() {
this.index >= 0 && this.index < this.steps.length && (this.blockEvent = !0, 0 === this.index && (this.scrollIcon.classList.add("hidden"), console.log("hided")), this.setHiddens(this.currentStep, "add"), r()({
targets: this.currentStep.header,
opacity: 0,
translateY: this.toDown ? "-50px" : "50px",
duration: .7 * this.duration,
easing: "easeInSine"
}), r()({
targets: this.currentStep,
opacity: 0,
translateY: [{
value: "-50%",
duration: 0
}, {
value: this.toDown ? "-90%" : "-10%",
duration: this.duration
}],
duration: this.duration,
easing: "easeInSine",
complete: this.showNextStep
}))
}
}, {
key: "showNextStep",
value: function() {
var t = this;
this.currentStep.style.visibility = "hidden";
var e = this.toDown ? this.nextStep : this.previousStep;
e.style.visibility = "", this.toDown ? this.index++ : this.index--, this.setIndex(), 0 === this.index && this.scrollIcon.classList.remove("hidden"), r()({
targets: this.cross,
rotate: [{
value: 0,
duration: 0
}, {
value: this.toDown ? 90 : -90,
duration: .7 * this.duration
}],
easing: "easeInOutSine"
}), r()({
targets: e.header,
opacity: [{
value: 0,
duration: 0
}, {
value: 1,
duration: .7 * this.duration
}],
translateY: [{
value: this.toDown ? "-50px" : "50px",
duration: 0
}, {
value: 0,
duration: .7 * this.duration
}],
easing: "easeOutSine"
}), r()({
targets: e,
opacity: [{
value: 0,
duration: 0
}, {
value: 1,
duration: this.duration
}],
translateY: [{
value: this.toDown ? "-10%" : "-90%",
duration: 0
}, {
value: "-50%",
duration: this.duration
}],
easing: "easeOutSine",
complete: function() {
t.blockEvent = !1, t.setHiddens(e, "remove")
}
})
}
}, {
key: "setIndex",
value: function() {
this.previousStep = this.steps[this.index - 1] || null, this.currentStep = this.steps[this.index], this.nextStep = this.steps[this.index + 1] || null
}
}]) && function(t, e) {
for (var i = 0; i < e.length; i++) {
var n = e[i];
n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
}
}(e.prototype, i), e
}(),
p = i(435);
p.keys().forEach(p), n.a.getInstance().define("scroll-steps", d)
}
},
[
[482, 0]
]
]);
Related
I have a webpage with a custom price slider. For desktop it works just fine and when I check it in google developer tools for mobile, it works too, but when I open the webpage with my phone, slider stops working properly, it does not change the plan column. How can I debug something like that?
http://sagemailer-17.eugeneskom.com/
that's the code being used for the slider
window.onload = () => {
const init = function() {
const breakpoints = [{
value: 0,
step: 12.5,
stepsSoFar: 0
},
{
value: 200,
step: 50,
stepsSoFar: 16
},
{
value: 1000,
step: 50,
stepsSoFar: 32
},
{
value: 2000,
step: 500,
stepsSoFar: 52
},
{
value: 10000,
step: 1000,
stepsSoFar: 68
},
{
value: 30000,
step: 5000,
stepsSoFar: 88
},
{
value: 100000,
step: 10000,
stepsSoFar: 102
},
{
value: 300000,
step: 50000,
stepsSoFar: 122
},
{
value: 1000000,
stepsSoFar: 136,
step: 1
}
];
const pricing = [
[200, 4, 0.2],
[500, 10, 0.01],
[1000, 15, 0.01],
[2000, 20, 0.005],
[7000, 50, 0.005],
[10000, 65, 0.0025],
[16000, 80, 0.0022],
[25000, 100, 0.006],
[30000, 130, 0.002],
[65000, 200, 0.002],
[100000, 270, 0.0015],
[200000, 420, 0.0015],
[300000, 570, 0.0006],
[600000, 750, 0.0006],
[700000, 810, 0.0006],
[800000, 870, 0.0006],
[900000, 930, 0.0006],
[1000000, 990, 0.001]
];
const planBgs = document.querySelectorAll(".StepRangeSlider__trackHeadItem");
const media = window.matchMedia("(max-width: 1024px)");
const minValue = 200;
const maxStep = breakpoints[breakpoints.length - 1].stepsSoFar;
const slider = document.getElementById("stepRangeSliderWrap");
const handle = document.getElementById("rangeSliderHandle");
const tooltip = document.getElementById("rangeSliderTooltip");
const plans = document.querySelectorAll(".plan-content .right .content");
let plansBreakPoints;
let valueBlock;
let emailsBlock;
let isHorizontal;
let value = 200;
let step = 18;
let pressed = false;
const checkRangeSliderVersion = () => {
if (media.matches) {
valueBlock = document.querySelectorAll(".display-price-mob");
emailsBlock = document.querySelectorAll(".emails-count");
isHorizontal = false;
} else {
valueBlock = document.querySelectorAll(".display-price");
emailsBlock = document.querySelectorAll(".emails-count");
isHorizontal = true;
}
plansBreakPoints = [
planBgs[1].getBoundingClientRect()[isHorizontal ? "left" : "top"],
planBgs[2].getBoundingClientRect()[isHorizontal ? "left" : "top"]
];
};
checkRangeSliderVersion();
media.addListener(checkRangeSliderVersion);
const getPriceForEmailsCount = emails => {
for (let i = pricing.length - 1; i >= 0; i--) {
if (emails === pricing[i][0]) {
return pricing[i][1];
}
if (emails > pricing[i][0]) {
return (emails - pricing[i][0]) * pricing[i + 1][2] + pricing[i][1];
}
}
return null;
};
const getValueForStep = step => {
const nearest = breakpoints.reduce((prev, curr) =>
curr.stepsSoFar < step && curr.stepsSoFar > prev.stepsSoFar ?
curr :
prev
);
const additionalValue = (step - nearest.stepsSoFar) * nearest.step;
return nearest.value + additionalValue;
};
const handleChange = () => {
const offset = (step / maxStep) * 100;
handle.style[isHorizontal ? "left" : "top"] = offset + "%";
tooltip.textContent = Math.floor(value);
valueBlock.forEach(e => {
e.textContent = getPriceForEmailsCount(value) + "$";
});
emailsBlock.forEach(e => {
e.textContent = Math.floor(value);
});
};
const handleMove = e => {
const client = isHorizontal ? e.clientX : e.clientY;
const sliderRect = slider.getBoundingClientRect();
let startPosition = isHorizontal ? sliderRect.left : sliderRect.top;
let endPosition = isHorizontal ? sliderRect.right : sliderRect.bottom;
if (client <= plansBreakPoints[0]) {
plans.forEach(e => {
e.style.display = "none";
});
plans[0].style.display = "block";
} else if (
client >= plansBreakPoints[0] &&
client <= plansBreakPoints[1]
) {
plans.forEach(e => {
e.style.display = "none";
});
plans[1].style.display = "block";
} else if (client >= plansBreakPoints[1]) {
plans.forEach(e => {
e.style.display = "none";
});
plans[2].style.display = "block";
}
if (!client) return;
let position;
if (client < startPosition) {
position = 0;
} else if (client > endPosition) {
position = endPosition - startPosition;
} else {
position = client - startPosition;
}
const currentStep = Math.round(
(position / (isHorizontal ? sliderRect.width : sliderRect.height)) *
maxStep
);
const currentStepValue = getValueForStep(currentStep);
if (
currentStepValue >= minValue &&
(currentStepValue !== value || currentStep !== step)
) {
value = currentStepValue;
step = currentStep;
handleChange();
}
};
const handleTouchMove = e => {
if (pressed) {
handleMouseMove(e.touches[0]);
}
};
const handleMouseUp = e => {
if (pressed) {
pressed = false;
}
};
const handleMouseMove = e => {
if (pressed) {
handleMove(e);
}
};
window.addEventListener("touchmove", handleTouchMove);
window.addEventListener("touchend", handleMouseUp);
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
slider.addEventListener("mousedown", function(e) {
e.preventDefault();
pressed = true;
handleMove(e);
});
slider.addEventListener("touchmove", e => {
e.preventDefault();
pressed = true;
handleMove(e.touches[0]);
});
handle.addEventListener("mousedown", function(e) {
e.preventDefault();
pressed = true;
handleMove(e);
});
handle.addEventListener("ontouchstart", function(e) {
e.preventDefault();
pressed = true;
handleMove(e.touches[0]);
});
};
init();
};
I am trying to get this slider to auto play but I can't seem to get it to workDoes anyone know how I can achieve this?
This is the slideshow:
Slideshow
Replace demo6.js code with given -
{
// From https://davidwalsh.name/javascript-debounce-function.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
class Slideshow {
constructor(el, settings) {
this.DOM = {};
this.DOM.el = el;
this.settings = {
animation: {
slides: {
duration: 500,
easing: 'easeOutQuint'
},
shape: {
duration: 300,
easing: {in: 'easeOutQuint', out: 'easeOutQuad'}
}
},
frameFill: 'url(#gradient1)'
}
this.settings.autoSlide = settings.autoSlide || false;
this.settings.autoSlideTimeout = settings.autoSlideTimeout || 4000;
this.init();
}
init() {
this.DOM.slides = Array.from(this.DOM.el.querySelectorAll('.slides--images > .slide'));
this.slidesTotal = this.DOM.slides.length;
this.DOM.nav = this.DOM.el.querySelector('.slidenav');
this.DOM.titles = this.DOM.el.querySelector('.slides--titles');
this.DOM.titlesSlides = Array.from(this.DOM.titles.querySelectorAll('.slide'));
this.DOM.nextCtrl = this.DOM.nav.querySelector('.slidenav__item--next');
this.DOM.prevCtrl = this.DOM.nav.querySelector('.slidenav__item--prev');
this.current = 0;
this.createFrame();
this.initEvents();
}
createFrame() {
this.rect = this.DOM.el.getBoundingClientRect();
this.frameSize = this.rect.width/12;
this.paths = {
initial: this.calculatePath('initial'),
final: this.calculatePath('final')
};
this.DOM.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.DOM.svg.setAttribute('class', 'shape');
this.DOM.svg.setAttribute('width','100%');
this.DOM.svg.setAttribute('height','100%');
this.DOM.svg.setAttribute('viewbox',`0 0 ${this.rect.width} ${this.rect.height}`);
this.DOM.svg.innerHTML = `
<defs>
<linearGradient id="gradient1" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#09012d"/>
<stop offset="100%" stop-color="#0f2b73"/>
</linearGradient>
</defs>
<path fill="${this.settings.frameFill}" d="${this.paths.initial}"/>`;
this.DOM.el.insertBefore(this.DOM.svg, this.DOM.titles);
this.DOM.shape = this.DOM.svg.querySelector('path');
}
updateFrame() {
this.paths.initial = this.calculatePath('initial');
this.paths.final = this.calculatePath('final');
this.DOM.svg.setAttribute('viewbox',`0 0 ${this.rect.width} ${this.rect.height}`);
this.DOM.shape.setAttribute('d', this.isAnimating ? this.paths.final : this.paths.initial);
}
calculatePath(path = 'initial') {
if ( path === 'initial' ) {
return `M 0,0 0,${this.rect.height} ${this.rect.width},${this.rect.height} ${this.rect.width},0 0,0 Z M 0,0 ${this.rect.width},0 ${this.rect.width},${this.rect.height} 0,${this.rect.height} Z`;
}
else {
const point1 = {x: this.rect.width/4-50, y: this.rect.height/4+50};
const point2 = {x: this.rect.width/4+50, y: this.rect.height/4-50};
const point3 = {x: this.rect.width-point2.x, y: this.rect.height-point2.y};
const point4 = {x: this.rect.width-point1.x, y: this.rect.height-point1.y};
return `M 0,0 0,${this.rect.height} ${this.rect.width},${this.rect.height} ${this.rect.width},0 0,0 Z M ${point1.x},${point1.y} ${point2.x},${point2.y} ${point4.x},${point4.y} ${point3.x},${point3.y} Z`;
}
}
initEvents() {
this.DOM.nextCtrl.addEventListener('click', () => this.navigate('next'));
this.DOM.prevCtrl.addEventListener('click', () => this.navigate('prev'));
window.addEventListener('resize', debounce(() => {
this.rect = this.DOM.el.getBoundingClientRect();
this.updateFrame();
}, 20));
document.addEventListener('keydown', (ev) => {
const keyCode = ev.keyCode || ev.which;
if ( keyCode === 37 ) {
this.navigate('prev');
}
else if ( keyCode === 39 ) {
this.navigate('next');
}
});
if(this.settings.autoSlide) {
setInterval(() => this.navigate('next'), this.settings.autoSlideTimeout);
}
}
navigate(dir = 'next') {
if ( this.isAnimating ) return false;
this.isAnimating = true;
const animateShapeIn = anime({
targets: this.DOM.shape,
duration: this.settings.animation.shape.duration,
easing: this.settings.animation.shape.easing.in,
d: this.paths.final
});
const animateSlides = () => {
return new Promise((resolve, reject) => {
const currentSlide = this.DOM.slides[this.current];
anime({
targets: currentSlide,
duration: this.settings.animation.slides.duration,
easing: this.settings.animation.slides.easing,
translateY: dir === 'next' ? this.rect.height : -1*this.rect.height,
complete: () => {
currentSlide.classList.remove('slide--current');
resolve();
}
});
const currentTitleSlide = this.DOM.titlesSlides[this.current];
anime({
targets: currentTitleSlide.children,
duration: this.settings.animation.slides.duration,
easing: this.settings.animation.slides.easing,
delay: (t,i,total) => dir === 'next' ? i*100 : (total-i-1)*100,
translateY: [0, dir === 'next' ? 100 : -100],
opacity: [1,0],
complete: () => {
currentTitleSlide.classList.remove('slide--current');
resolve();
}
});
this.current = dir === 'next' ?
this.current < this.slidesTotal-1 ? this.current + 1 : 0 :
this.current > 0 ? this.current - 1 : this.slidesTotal-1;
const newSlide = this.DOM.slides[this.current];
newSlide.classList.add('slide--current');
anime({
targets: newSlide,
duration: this.settings.animation.slides.duration,
easing: this.settings.animation.slides.easing,
translateY: [dir === 'next' ? -1*this.rect.height : this.rect.height,0]
});
const newSlideImg = newSlide.querySelector('.slide__img');
anime.remove(newSlideImg);
anime({
targets: newSlideImg,
duration: this.settings.animation.slides.duration*3,
easing: this.settings.animation.slides.easing,
translateY: [dir === 'next' ? -100 : 100, 0],
scale: [0.2,1]
});
const newTitleSlide = this.DOM.titlesSlides[this.current];
newTitleSlide.classList.add('slide--current');
anime({
targets: newTitleSlide.children,
duration: this.settings.animation.slides.duration*1.5,
easing: this.settings.animation.slides.easing,
delay: (t,i,total) => dir === 'next' ? i*100+100 : (total-i-1)*100+100,
translateY: [dir === 'next' ? -100 : 100 ,0],
opacity: [0,1]
});
});
};
const animateShapeOut = () => {
anime({
targets: this.DOM.shape,
duration: this.settings.animation.shape.duration,
easing: this.settings.animation.shape.easing.out,
d: this.paths.initial,
complete: () => this.isAnimating = false
});
}
animateShapeIn.finished.then(animateSlides).then(animateShapeOut);
}
};
new Slideshow(document.querySelector('.slideshow'), {
autoSlide: true,
autoSlideTimeout: 4000 // 4 second
});
imagesLoaded('.slide__img', { background: true }, () => document.body.classList.remove('loading'));
};
I have added settings -
new Slideshow(document.querySelector('.slideshow'), {
autoSlide: true,
autoSlideTimeout: 4000 // 4 second
});
You may code diff to see the changes I have made.
There is a chart that shows the statistics , production has been sold in any quantity in any city.
enter image description here
I need to add another value , for what amount it was sold . On the second day I'm sitting , I can not figure out how to do it .
here is the link
function ev(str) {
eval(str)
}
function regression(x, y, typ) {
var type = (typ == null) ? 'linear' : typ;
var N = x.length;
var slope;
var intercept;
var SX = 0;
var SY = 0;
var SXX = 0;
var SXY = 0;
var SYY = 0;
var Y = [];
var X = [];
if (type == 'linear') {
X = x;
Y = y;
} else if (type == 'exp' || type == 'exponential') {
for (var i = 0; i < y.length; i++) {
// ignore points <= 0, log undefined.
if (y[i] <= 0) {
N = N - 1;
} else {
X.push(x[i]);
Y.push(Math.log(y[i]));
}
}
}
for (var i = 0; i < N; i++) {
SX = SX + X[i];
SY = SY + Y[i];
SXY = SXY + X[i] * Y[i];
SXX = SXX + X[i] * X[i];
SYY = SYY + Y[i] * Y[i];
}
slope = (N * SXY - SX * SY) / (N * SXX - SX * SX);
intercept = (SY - slope * SX) / N;
return [slope, intercept];
}
function linearRegression(X, Y) {
var ret;
ret = regression(X, Y, 'linear');
return [ret[0], ret[1]];
}
function expRegression(X, Y) {
var ret;
var x = X;
var y = Y;
ret = regression(x, y, 'exp');
var base = Math.exp(ret[0]);
var coeff = Math.exp(ret[1]);
return [base, coeff];
}
function fitData(data, typ) {
var type = (typ == null) ? 'linear' : typ;
var ret;
var res;
var x = [];
var y = [];
var ypred = [];
for (i = 0; i < data.length; i++) {
if (data[i] != null && Object.prototype.toString.call(data[i]) === '[object Array]') {
if (data[i] != null && data[i][0] != null && data[i][1] != null) {
x.push(data[i][0]);
y.push(data[i][1]);
}
} else if (data[i] != null && typeof data[i] === 'number') { //If type of X axis is category
x.push(i);
y.push(data[i]);
} else if (data[i] != null && Object.prototype.toString.call(data[i]) === '[object Object]') {
if (data[i] != null && data[i].x != null && data[i].y != null) {
x.push(data[i].x);
y.push(data[i].y);
}
}
}
if (type == 'linear') {
ret = linearRegression(x, y);
for (var i = 0; i < x.length; i++) {
res = ret[0] * x[i] + ret[1];
ypred.push([x[i], res]);
}
return {
data: ypred,
slope: ret[0],
intercept: ret[1],
y: function(x) {
return (this.slope * x) + this.intercept;
},
x: function(y) {
return (y - this.intercept) / this.slope;
}
};
} else if (type == 'exp' || type == 'exponential') {
ret = expRegression(x, y);
for (var i = 0; i < x.length; i++) {
res = ret[1] * Math.pow(ret[0], x[i]);
ypred.push([x[i], res]);
}
ypred.sort();
return {
data: ypred,
base: ret[0],
coeff: ret[1]
};
}
}
function showGraph(zero) {
zero = typeof zero === "undefined" ? true : zero
sourceData.sort(function(a, b) {
return a[0] - b[0]
})
series = {}
seriesSum = []
dateStart = new Date(sourceData[0][0].toString().replace(/(\d{4})(\d{2})(\d{2})/g, "$1-$2-$3"))
dateEnd = new Date(sourceData[sourceData.length - 1][0].toString().replace(/(\d{4})(\d{2})(\d{2})/g, "$1-$2-$3"))
sourceData.map(function(entry) {
var date = new Date(entry[0].toString().replace(/(\d{4})(\d{2})(\d{2})/g, "$1-$2-$3"))
var microtime = date.getTime()
var dealer = entry[2]
var sum = entry[3]
//int
if (typeof entry[1] === "undefined") {
entry[1] = 0
}
//create group
if (typeof series[dealer] === "undefined") {
series[dealer] = []
}
//find similar day
if (series[dealer].length > 0 && series[dealer][series[dealer].length - 1][0] === microtime) {
series[dealer][series[dealer].length - 1][1] += entry[1]
} else {
series[dealer].push([microtime, entry[1]])
}
//mixed sum
if (seriesSum.length > 0 && seriesSum[seriesSum.length - 1][0] === microtime) {
seriesSum[seriesSum.length - 1][1] += entry[1]
} else {
seriesSum.push([microtime, entry[1]])
}
})
seriesByName = {}
seriesArray = []
_.map(series, function(days, dealer) {
var newDays = []
if (zero) {
for (var dateTemp = new Date(dateStart.getTime()), i = 0; dateTemp < dateEnd; dateTemp.setDate(dateTemp.getDate() + 1)) {
var microtime = dateTemp.getTime()
try {
if (days[i][0] == microtime) {
newDays.push(days[i])
i++
} else {
newDays.push([microtime, 0])
}
} catch (error) {}
}
} else {
newDays = days
}
seriesByName[dealer] = newDays
seriesArray.push({
name: dealer,
data: newDays,
id: dealer,
dataGrouping: {
approximation: "sum",
enabled: true,
forced: true,
units: [
['day', [1]]
],
dateTimeLabelFormats: {
week: ['За 7 дней начиная от "%A, %b %e, %Y"', '%A, %b %e', '-%A, %b %e, %Y']
}
}
})
})
graphContainer = $('#graph').highcharts('StockChart', {
rangeSelector: {
buttons: [, {
type: 'month',
count: 1,
text: '1м'
}, {
type: 'month',
count: 2,
text: '2м'
}, {
type: 'month',
count: 6,
text: '6м'
}, {
type: 'year',
count: 1,
text: '1г'
}, {
type: 'all',
text: 'Весь'
}],
selected: 5
},
tooltip: {
//pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
animation: false,
valueDecimals: 0
},
yAxis: [{
/*labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},*/
}, {
labels: {
enabled: false
}
}],
plotOptions: {
series: {
//compare: 'percent'
}
},
series: seriesArray,
legend: {
align: 'center',
verticalAlign: 'bottom',
layout: 'horizontal',
enabled: true
}
})
graph = graphContainer.highcharts()
grouped = false
$('#groupWeek').on('click', function() {
for (var i = 0; i < graph.series.length; i++) {
var serie = graph.series[i]
if (grouped) {
serie.update({
dataGrouping: {
units: [
['day', [1]]
]
}
})
} else {
serie.update({
dataGrouping: {
units: [
['week', [1]]
]
}
})
}
}
grouped = grouped ? false : true
if (grouped) {
$(this).text('Убрать группировку')
} else {
$(this).text('Группировать по неделям')
}
})
percent = false
$('#changePercent').on('click', function() {
for (var i = 0; i < graph.series.length; i++) {
var serie = graph.series[i]
if (percent) {
serie.update({
compare: 'value'
})
} else {
serie.update({
compare: 'percent'
})
}
}
percent = percent ? false : true
if (percent) {
$(this).text('Представить в значениях')
} else {
$(this).text('Представить в процентах')
}
})
trend = false
trendArrayId = []
$('#showTrendline').on('click', function() {
if (grouped) $('#groupWeek').trigger('click')
if (trend) {
while (trendArrayId.length) {
graph.get(trendArrayId.pop()).remove()
}
} else {
var countSeries = graph.series.length
for (var iteratorSeries = 0; iteratorSeries < countSeries; iteratorSeries++) {
var serie = graph.series[iteratorSeries]
if (serie.name !== 'Navigator') {
var data = fitData(seriesByName[serie.name]).data
trendArrayId.push('trend_' + serie.name)
graph.addSeries({
data: data,
color: serie.color,
visible: serie.visible,
linkedTo: serie.name,
name: 'Тенденция (' + serie.name + ')',
id: 'trend_' + serie.name,
dataGrouping: {
approximation: "sum",
enabled: true,
forced: true,
units: [
['day', [1]]
]
}
})
}
}
}
trend = trend ? false : true
if (trend) {
$(this).text('Убрать линии тенденции')
} else {
$(this).text('Вывести линии тенденции')
}
})
}
var sourceData = [
[20140829, 63, "Москва и МО", 100],
[20140930, 1, "Краснодар", 100],
[20140819, 1, "Краснодар", 100],
[20141120, 1, "Краснодар", 100],
[20141010, 1, "Краснодар", 100],
[20141003, 2, "Краснодар", 100],
[20140825, 81, "Москва и МО", 100],
[20140822, 77, "Москва и МО", 100],
[20140918, 90, "Москва и МО", 100],
[20140930, 128, "Москва и МО", 100],
[20141031, 85, "Москва и МО", 100],
[20140827, 105, "Москва и МО", 100],
[20141027, 141, "Москва и МО", 100],
];
if (!oldBrowser) {
$(showGraph(false));
}
One option would be to add a hidden series with your extra value to the chart series: { visible: false ... } and display the value only in the tooltip.
You can override the tooltip formatter using the following property:
http://api.highcharts.com/highcharts#tooltip.formatter
Ensuring you have tooltip: { shared: true ... } setting, you can access all series values for a given x value.
This gives you the flexibility to use a hidden series OR another option would be to have a reference dictionary that you can use to look up your extra value (using the x value as the key) and render it in the tooltip.
I am trying to integrate WebRTC remote stream with WebAudio. I am using wavesurfer (https://github.com/katspaugh/wavesurfer.js) to accomplish this. When I attach the local stream, it plays well. When I attach the remote stream, buffer contents are filled with zeros and I see no activity. How to fix this?
My Code:
if (this.remoteStream_ != null) {
if (this.wavesurfer_ == null) {
var parent = this;
this.wavesurfer_ = Object.create(WaveSurfer);
this.wavesurfer_.init({
container: '#waveform',
waveColor: '#fff'
});
this.wavesurferStream_ = Object.create(WaveSurfer.Streamer);
this.wavesurferStream_.init({
wavesurfer: this.wavesurfer_
});
// start the microphone
this.wavesurferStream_.start(this.remoteStream_);
this.audioWaveIconSet_.on();
} else {
if (this.wavesurferStream_ != null) {
this.wavesurferStream_.destroy();
this.wavesurferStream_ = null;
}
this.wavesurfer_.destroy();
this.wavesurfer_ = null;
this.audioWaveIconSet_.off();
}
}
Wavesurfer Plugin for Streams:
/*! wavesurfer.js 1.0.57 (Thu, 25 Feb 2016 17:09:20 GMT)
* https://github.com/katspaugh/wavesurfer.js
* #license CC-BY-3.0 */
! function(a, b) {
"function" == typeof define && define.amd ? define(["wavesurfer"], function(a) {
return b(a)
}) : "object" == typeof exports ? module.exports = b(require("wavesurfer.js")) : b(WaveSurfer)
}(this, function(a) {
"use strict";
a.Streamer = {
init: function(a) {
this.params = a;
this.wavesurfer = a.wavesurfer;
if (!this.wavesurfer) throw new Error("No WaveSurfer instance provided");
this.active = !1, this.paused = !1, this.reloadBufferFunction = this.reloadBuffer.bind(this);
this.bufferSize = this.params.bufferSize || 4096, this.numberOfInputChannels = this.params.numberOfInputChannels || 1, this.numberOfOutputChannels = this.params.numberOfOutputChannels || 1, this.micContext = this.wavesurfer.backend.getAudioContext();
},
start: function(stream) {
this.gotStream(stream);
},
togglePlay: function() {
this.active ? (this.paused = !this.paused, this.paused ? this.pause() : this.play()) : this.start()
},
play: function() {
this.paused = !1, this.connect()
},
pause: function() {
this.paused = !0, this.disconnect()
},
stop: function() {
this.active && (this.stopDevice(), this.wavesurfer.empty())
},
stopDevice: function() {},
connect: function() {
void 0 !== this.stream && (this.mediaStreamSource = this.micContext.createMediaStreamSource(this.stream), this.levelChecker = this.micContext.createScriptProcessor(this.bufferSize, this.numberOfInputChannels, this.numberOfOutputChannels), this.mediaStreamSource.connect(this.levelChecker), this.levelChecker.connect(this.micContext.destination), this.levelChecker.onaudioprocess = this.reloadBufferFunction)
},
disconnect: function() {
void 0 !== this.mediaStreamSource && this.mediaStreamSource.disconnect(), void 0 !== this.levelChecker && (this.levelChecker.disconnect(), this.levelChecker.onaudioprocess = void 0)
},
reloadBuffer: function(a) {
this.paused || (this.wavesurfer.empty(), this.wavesurfer.loadDecodedBuffer(a.inputBuffer))
},
gotStream: function(a) {
this.stream = a, this.active = !0, this.play()
},
destroy: function(a) {
this.paused = !0, this.stop()
},
deviceError: function(a) {},
extractVersion: function(a, b, c) {
var d = a.match(b);
return d && d.length >= c && parseInt(d[c], 10)
},
detectBrowser: function() {
var a = {};
return a.browser = null, a.version = null, a.minVersion = null, "undefined" != typeof window && window.navigator ? navigator.mozGetUserMedia ? (a.browser = "firefox", a.version = this.extractVersion(navigator.userAgent, /Firefox\/([0-9]+)\./, 1), a.minVersion = 31, a) : navigator.webkitGetUserMedia && window.webkitRTCPeerConnection ? (a.browser = "chrome", a.version = this.extractVersion(navigator.userAgent, /Chrom(e|ium)\/([0-9]+)\./, 2), a.minVersion = 38, a) : navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/) ? (a.browser = "edge", a.version = this.extractVersion(navigator.userAgent, /Edge\/(\d+).(\d+)$/, 2), a.minVersion = 10547, a) : (a.browser = "Not a supported browser.", a) : (a.browser = "Not a supported browser.", a)
}
}, a.util.extend(a.Streamer, a.Observer)
}), ! function(a, b) {
"function" == typeof define && define.amd ? define(["wavesurfer"], function(a) {
return b(a)
}) : "object" == typeof exports ? module.exports = b(require("wavesurfer.js")) : b(WaveSurfer)
}(this, function(a) {
"use strict";
a.Streamer = {
init: function(a) {
if (this.params = a, this.wavesurfer = a.wavesurfer, !this.wavesurfer) throw new Error("No WaveSurfer instance provided");
this.active = !1, this.paused = !1, this.reloadBufferFunction = this.reloadBuffer.bind(this);
this.bufferSize = this.params.bufferSize || 4096, this.numberOfInputChannels = this.params.numberOfInputChannels || 1, this.numberOfOutputChannels = this.params.numberOfOutputChannels || 1, this.micContext = this.wavesurfer.backend.getAudioContext();
},
start: function(stream) {
this.gotStream(stream);
},
togglePlay: function() {
this.active ? (this.paused = !this.paused, this.paused ? this.pause() : this.play()) : this.start()
},
play: function() {
this.paused = !1, this.connect()
},
pause: function() {
this.paused = !0, this.disconnect()
},
stop: function() {
this.active && (this.stopDevice(), this.wavesurfer.empty())
},
stopDevice: function() {},
connect: function() {
void 0 !== this.stream && (this.mediaStreamSource = this.micContext.createMediaStreamSource(this.stream), this.levelChecker = this.micContext.createScriptProcessor(this.bufferSize, this.numberOfInputChannels, this.numberOfOutputChannels), this.mediaStreamSource.connect(this.levelChecker), this.levelChecker.connect(this.micContext.destination), this.levelChecker.onaudioprocess = this.reloadBufferFunction)
},
disconnect: function() {
void 0 !== this.mediaStreamSource && this.mediaStreamSource.disconnect(), void 0 !== this.levelChecker && (this.levelChecker.disconnect(), this.levelChecker.onaudioprocess = void 0)
},
reloadBuffer: function(a) {
this.paused || (this.wavesurfer.empty(), this.wavesurfer.loadDecodedBuffer(a.inputBuffer))
},
gotStream: function(a) {
this.stream = a, this.active = !0, this.play()
},
destroy: function(a) {
this.paused = !0, this.stop()
},
deviceError: function(a) {},
extractVersion: function(a, b, c) {
var d = a.match(b);
return d && d.length >= c && parseInt(d[c], 10)
},
detectBrowser: function() {
var a = {};
return a.browser = null, a.version = null, a.minVersion = null, "undefined" != typeof window && window.navigator ? navigator.mozGetUserMedia ? (a.browser = "firefox", a.version = this.extractVersion(navigator.userAgent, /Firefox\/([0-9]+)\./, 1), a.minVersion = 31, a) : navigator.webkitGetUserMedia && window.webkitRTCPeerConnection ? (a.browser = "chrome", a.version = this.extractVersion(navigator.userAgent, /Chrom(e|ium)\/([0-9]+)\./, 2), a.minVersion = 38, a) : navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/) ? (a.browser = "edge", a.version = this.extractVersion(navigator.userAgent, /Edge\/(\d+).(\d+)$/, 2), a.minVersion = 10547, a) : (a.browser = "Not a supported browser.", a) : (a.browser = "Not a supported browser.", a)
}
}, a.util.extend(a.Streamer, a.Observer)
});
This is a known chrome issue: Hook up Web Audio API with WebRTC for audio processing
After long wait, I guess it has finally been fixed in version 49. Try updating your chrome.
You can check if it works in this Demo app
I'm making an application and I have to display data in a chart. I also only want the last 5 transactions entered to display.
I'm using Backbone.js and Chart.js. In my prototype displaying data was no problem because I just bootstrapped the data. But now that I'm trying to pull the data from my Backbone Collection it's not working. I only get a transparent image
// Model
(function (exports) {
var Transaction = Backbone.Model.extend({
defaults: {
amount: 0,
transactionDate: "",
transactionType: "debit",
category: "miscellaneous",
description: ""
},
categories: [
"salary",
"rent",
"miscellaneous"
],
transactionTypes: [
"credit",
"debit"
],
initialize: function() {
this.set({transactionDate: this.attributes.transactionDate || Date.now()}, {validate: true});
},
validate: function(attrs, options) {
if (attrs['transactionType'] !== undefined &&
!_.contains(this.transactionTypes, attrs['transactionType'].toLowerCase())) {
return 'Invalid type: ' + attrs['transactionType'];
} else if (attrs['category'] !== undefined &&
!_.contains(this.categories, attrs['category'].toLowerCase())) {
return 'Invalid category: ' + attrs['category'];
} else if (attrs['transactionDate'] !== undefined &&
_.isNaN(parseInt(attrs['transactionDate'])) || attrs['transactionDate'] < 0) {
return 'Invalid date: '+ attrs['transactionDate'];
} else if (attrs['amount'] !== undefined &&
_.isNaN(parseInt(attrs['amount'])) || attrs['amount'] < 0) {
return 'Invalid amount: '+ attrs['amount'];
}
return null;
}
});
// export for global use
exports.expensus.Models.Transaction = Transaction;
}(this));
This is the collection I'm using ..
;(function (exports) {
var Transactions = Backbone.Collection.extend({
// stuff and thangs
model: expensus.Models.Transaction,
localStorage: new Backbone.LocalStorage('TransactionsCollection'),
latestFive: function(toJSON) {
this.sortByDate(-1); // sort latest first
if (!toJSON) {
return _.first(this.models, 5);
} else {
var models = _.first(this.models, 5),
idx = -1,
json = [],
model;
while (model = models[++idx]) {
json.push(model.attributes);
}
return json;
}
},
sortByDate: function(dir) {
dir = dir || -1;
this.comparator = function(transaction) {
return dir * transaction.get("transactionDate");
};
this.sort();
},
sortByAmount: function(dir) {
dir = dir || -1;
this.comparator = function(transaction) {
return dir * transaction.get("amount");
};
this.sort();
}
});
exports.expensus.Collections.Transactions = Transactions;
}(this));
And this is the Chart View, I get no errors in dev tools so I'm really at a loss ...
;(function (exports){
var ChartView = Backbone.View.extend({
el: ".home-page",
template: Handlebars.compile($("#chart-template").html()),
chart: null,
initialize: function () {
this.listenTo(this.collection, "add", this.render);
this.listenTo(this.collection, "change", this.render);
this.$(".chart-view-div").html(this.template());
this.chart = new Chart($("#expense-chart")[0].getContext("2d"));
this.render();
},
render: function() {
var self = this;
var data = this.chartData();
self.chart.Doughnut(data, {
responsive: true,
animateScale: true
});
},
chartData: function() {
var collection = this.collection.latestFive(true);
var data = {
vals: [],
labels: [],
allData: []
};
var getData = function(color, highlight, labels, vals, collection) {
var object = {
color: color,
highlight: highlight,
chartData: [
{
value: "",
label: ""
}
]
};
for (var i = 0; i < labels.length; i++ ) {
object.chartData.push(0);
}
for (var j = 0; j < vals.length; j++ ) {
object.chartData.push(0);
}
for (var i = 0; i < collection.length; i++ ) {
var item = collection[i];
var label = labels.indexOf(item.category);
var val = vals.indexOf(item.amount);
object.chartData[ { value: val, label: label } ]++;
}
return object;
};
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
for (var i = 0; i < collection.length; i++ ) {
var object = collection[i];
var color = getRandomColor();
var highlight = getRandomColor();
data.labels.push(object.category);
data.vals.push(object.amount);
data.allData.push(getData(color, highlight, data.labels, data.vals, collection));
}
return data;
}
});
exports.expensus.Views.ChartView = ChartView;
}(this));
My Add Transaction View
;(function (exports) {
var AddTransactionView = Backbone.View.extend({
el: "#add-transaction-page",
events: {
"submit .add-transaction-form": "addTransaction"
},
initialize: function() {
this.form = this.$(".add-transaction-form")[0];
},
addTransaction: function(evt) {
if (evt) {
evt.preventDefault();
}
var m = new expensus.Models.Transaction({
transactionDate: Date.now(),
transactionType: this.form["trans-type"].value,
amount: this.form["trans-amount"].value,
description: this.form["trans-description"].value,
category: this.form["trans-category"].value
});
if(m.validationError === null) {
this.collection.add(m);
m.save();
$(this.el).modal("hide");
this.form.reset();
} else {
alert("Model is invalid: " + m.validationError);
}
}
});
exports.expensus.Views.AddTransactionView = AddTransactionView;
}(this));
This is as far as I could get. I've done this before with a different kind of chart but can't for the life of me figure it out with the Doughnut chart.
Thanks, everyone
The main thing i can see is that you pass the chart data which is not in the format that chartjs expects, so it should be an array of objects which have the properties value label and color but you are passing it something different. so a quick fix for that would be to construct an array as described
// Model
var Transaction = Backbone.Model.extend({
defaults: {
amount: 0,
transactionDate: "",
transactionType: "debit",
category: "miscellaneous",
description: ""
},
categories: [
"salary",
"rent",
"miscellaneous"
],
transactionTypes: [
"credit",
"debit"
],
initialize: function() {
this.set({
transactionDate: this.attributes.transactionDate || Date.now()
}, {
validate: true
});
},
validate: function(attrs, options) {
if (attrs['transactionType'] !== undefined && !_.contains(this.transactionTypes, attrs['transactionType'].toLowerCase())) {
return 'Invalid type: ' + attrs['transactionType'];
} else if (attrs['category'] !== undefined && !_.contains(this.categories, attrs['category'].toLowerCase())) {
return 'Invalid category: ' + attrs['category'];
} else if (attrs['transactionDate'] !== undefined && _.isNaN(parseInt(attrs['transactionDate'])) || attrs['transactionDate'] < 0) {
return 'Invalid date: ' + attrs['transactionDate'];
} else if (attrs['amount'] !== undefined && _.isNaN(parseInt(attrs['amount'])) || attrs['amount'] < 0) {
return 'Invalid amount: ' + attrs['amount'];
}
return null;
}
});
var Transactions = Backbone.Collection.extend({
// stuff and thangs
model: Transaction,
latestFive: function(toJSON) {
this.sortByDate(-1); // sort latest first
if (!toJSON) {
return _.first(this.models, 5);
} else {
var models = _.first(this.models, 5),
idx = -1,
json = [],
model;
while (model = models[++idx]) {
json.push(model.attributes);
}
return json;
}
},
sortByDate: function(dir) {
dir = dir || -1;
this.comparator = function(transaction) {
return dir * transaction.get("transactionDate");
};
this.sort();
},
sortByAmount: function(dir) {
dir = dir || -1;
this.comparator = function(transaction) {
return dir * transaction.get("amount");
};
this.sort();
}
});
var ChartView = Backbone.View.extend({
el: ".home-page",
template: Handlebars.compile($("#chart-template").html()),
chart: null,
initialize: function() {
this.listenTo(this.collection, "add", this.render);
this.listenTo(this.collection, "change", this.render);
this.$(".chart-view-div").html(this.template());
this.chart = new Chart(this.$("#expense-chart")[0].getContext("2d"));
this.render();
},
render: function() {
var self = this;
var data = this.chartData();
this.chart.Doughnut(data, {
responsive: true,
animateScale: true
});
},
chartData: function() {
var collection = this.collection.latestFive(true);
var data = [];;
var getData = function(color, highlight, labels, vals, collection) {
var object = {
color: color,
highlight: highlight,
chartData: [{
value: "",
label: ""
}]
};
for (var i = 0; i < labels.length; i++) {
object.chartData.push(0);
}
for (var j = 0; j < vals.length; j++) {
object.chartData.push(0);
}
for (var i = 0; i < collection.length; i++) {
var item = collection[i];
var label = labels.indexOf(item.category);
var val = vals.indexOf(item.amount);
object.chartData[{
value: val,
label: label
}] ++;
}
return object;
};
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
for (var i = 0; i < collection.length; i++) {
var object = collection[i];
var color = getRandomColor();
var highlight = getRandomColor();
data.push({
value: object.amount,
color: color,
label: object.category
});
}
return data;
}
});
var collection = new Transactions([{
amount: 12,
transactionDate: 1417442176000,
transactionType: "debit",
category: "miscellaneous",
description: ""
}, {
amount: 13,
transactionDate: 1417442176000,
transactionType: "credit",
category: "salary",
description: ""
}]);
var view = new ChartView({
collection: collection
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone.js"></script>
<script src="http://www.chartjs.org/assets/Chart.min.js"></script>
<script id="chart-template" type="text/x-handlebars-template">
<canvas id="expense-chart"></canvas>
</script>
<div class="home-page">
<div class="chart-view-div"></div>
</div>