7
\$\begingroup\$

The code below is loading an svg into the canvas via RaphaelJS. There are mouseover/mouseout events, on click on an element of the svg, and drag/zoom.

I would like to know, what are some good practices, or how to improve the productivity and maybe shorten my code. One issues may be that I use a lot of iterations through the elements(~2000-3000) on the svg image. This is not the only "problem" in my code, so if anyone has any ideas, I am ready to try them.

Raphael.fn.select = (selector) ->
 type = selector.charAt(0)
 selector = selector.substr(1)
 attr = if type == '.' then 'class' else 'id'
 els = []
 bot = this.bottom
 while bot
 if bot.node.getAttribute(attr) == selector
 els.push(bot)
 bot = bot.next
 return if type == '.' then els else els[0] or null
;((window) ->
 'use strict'
 loadSVG = (file) ->
 response = null
 $.ajax({
 type: 'GET',
 url: file,
 dataType: 'xml',
 async: false,
 success: (svgXML) ->
 response = svgXML
 })
 return response
 selectedPoints = []
 disabledPoints = ['seggiolino_1637', 'seggiolino_1881', 'seggiolino_1984', 'seggiolino_889', 'seggiolino_891', 'seggiolino_893', 'seggiolino_890', 'seggiolino_892', 'seggiolino_894']
 settings =
 clickAnimTime: 0
 hoverScale: 2
 animTime: 300
 animEase: 'backOut'
 scale: 3
 vb:
 x: 0
 y: 0
 width: 1606
 height: 1039
 paper:
 width: 800
 height: 480
 states =
 default:
 transform: ''
 fill: '#008000'
 'stroke-width': 0
 hover:
 transform: 's' + settings.hoverScale
 disabled:
 fill: '#eaeaea'
 'stroke-width': 1
 stroke: '#333333'
 selected:
 transform: 's' + settings.hoverScale
 fill: '#AA8834'
 'stroke-width': 2
 stroke: '#AA8834'
 container = document.getElementById('mapContainer')
 paper = new Raphael(container, settings.vb.width, settings.vb.height)
 map = paper.importSVG(loadSVG('img/svgscala.svg'))
 draggable = container.getElementsByTagName('svg')[0]
 paper.setSize(settings.paper.width, settings.paper.height)
 viewBoxWidth = settings.vb.width
 viewBoxHeight = settings.vb.height
 dx = 0
 dy = 0
 oX = 0
 oY = 0
 oWidth = viewBoxWidth
 oHeight = viewBoxHeight
 mousedown = false
 startX = 0
 startY = 0
 viewBox = paper.setViewBox(oX, oY, viewBoxWidth, viewBoxHeight, true)
 viewBox.x = oX
 viewBox.y = oY
 zoomLevel = 0
 firedCallback = false
 paper.select('#' + point).attr(states.disabled) for point in disabledPoints
 map.hover(() ->
 if disabledPoints.indexOf(this.node.getAttribute('id')) == -1
 this[0].style.cursor = 'pointer'
 this.animate(states.hover, settings.clickAnimTime, settings.animEase)
 else
 this[0].style.cursor = 'not-allowed'
 , () ->
 if disabledPoints.indexOf(this.node.getAttribute('id')) == -1
 if selectedPoints.indexOf(this.node.getAttribute('id')) == -1
 this.animate(states.default, settings.clickAnimTime, settings.animEase)
 )
 map.click(() ->
 cx = this.attr('cx')
 cy = this.attr('cy')
 if disabledPoints.indexOf(this.node.getAttribute('id')) == -1
 if selectedPoints.indexOf(this.node.getAttribute('id')) == -1
 selectedPoints.push(this.node.getAttribute('id'))
 this.animate(states.selected, settings.clickAnimTime, settings.animEase)
 else
 removeId = selectedPoints.indexOf(this.node.getAttribute('id'))
 selectedPoints.splice(removeId, 1)
 this.animate(states.default, settings.clickAnimTime, settings.animEase)
 )
 wheel = (e) ->
 e = e or window.event
 delta = 0
 if e.wheelDelta
 delta = e.wheelDelta / 120
 else if e.detail
 delta = -e.detail / 3
 if delta then handle(e, delta)
 handleAreas()
 if e.preventDefault then e.preventDefault()
 return e.returnValue = false
 handle = (e, delta) ->
 vBOw = viewBoxWidth
 vBOh = viewBoxHeight
 factor = 0
 if delta > 0
 zoomLevel++
 viewBoxWidth *= 0.95
 viewBoxHeight *= 0.95
 factor = 0.95
 else
 zoomLevel--
 viewBoxWidth *= 1.05
 viewBoxHeight *= 1.05
 factor = 1.05
 viewBox.x -= (e.pageX - (viewBoxWidth - vBOw)) * (factor - 1)
 viewBox.y -= (e.pageY - (viewBoxHeight - vBOh)) * (factor - 1)
 paper.setViewBox(viewBox.x, viewBox.y, viewBoxWidth, viewBoxHeight)
 draggable.onmousedown = (e) ->
 if paper.getElementByPoint(e.pageX, e.pageY) != null
 return
 e = e or window.event
 mousedown = true
 startX = e.pageX
 startY = e.pageY
 document.onmousemove = (e) ->
 if mousedown == false then return
 document.body.style.cursor = '-webkit-grabbing'
 e = e or window.event
 dx = startX - e.pageX
 dy = startY - e.pageY
 x = viewBoxWidth / paper.width
 y = viewBoxHeight / paper.height
 dx *= x
 dy *= y
 paper.setViewBox(viewBox.x + dx, viewBox.y + dy, viewBoxWidth, viewBoxHeight)
 document.onmouseup = (e) ->
 document.body.style.cursor = 'initial'
 if mousedown == false then return
 e = e or window.event
 viewBox.x += dx
 viewBox.y += dy
 mousedown = false
 handleAreas = () ->
 if zoomLevel > 30
 if not firedCallback
 firedCallback = true
 a.attr('fill', '') for a in paper.select('.area')
 console.log 'zoomed in'
 else
 if firedCallback
 firedCallback = false
 a.attr('fill', 'red') for a in paper.select('.area')
 draggable.addEventListener('DOMMouseScroll', wheel, false)
 draggable.onmousewheel = draggable.onmousewheel = wheel
)(window)

Maybe some of you know a shorthand expression in CoffeeScript, or maybe you can suggest a nice trick in JS. The code works fine, but I won't say I'm happy with it. I will post the code in compiled JavaScript if someone needs it.

asked Nov 3, 2016 at 10:06
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$
wheel = (e) ->
 e = e or window.event
 # the code follows

Here you want to set argument e to some default value if e is missing. CoffeeScript allows you to set default value of an argument right in the function signature:

wheel = (e = window.event) ->
 # the code follows

Also there are some alternative solutions (perhaps more favorable in CoffeeScript):

e ||= window.event
# sets e to window.event if e evaluates to false
# null, unefined, 0, "", NaN and false values will be replaced
# same as `e || (e = window.event)`

and

e ?= window.event
# sets e to window.event only if e is null or undefined
# 0, "" and other falsy friends are allowed
# same as `if (e == null) { e = window.event }`

The operator ? in the latter form is special. It is called The Existential Operator. I guess it is the prefered way to set a variable to default value or test for it existence.


You can omit () from () -> function signature since there are no arguments. The possible shortest function signature in CoffeeScript is ->, same as function() {} in JavaScript.


if e.preventDefault then e.preventDefault()

may be written as

e.preventDefault?()

Notice the ? operator before (). It will test if e.preventDefault exists and is actually a function before running it.


if delta then handle(e, delta)

may be

handle(e, delta) if delta
answered Jun 22, 2018 at 10:18
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.