HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Drag and Drop Schedule for Community Radio Station

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
communitydragradiostationdropforandschedule

Problem

I'm working on the backend of a community radio station website, and fancied trying my hand at writing a drag and drop scheduler.

It's working, but I feel I've made a mess with the drag and drop maths. What's the best way to handle an elements position in JavaScript?

I've used a combination of offsets from .pageX, .getBoundsClientRect and .offsetLeft etc. but I had a real struggle getting them to work together, I'm sure there must be some standard way to handle this stuff.

I'm not much cop with JavaScript so any style or structure advice would be appreciated and if someone could offer some advice on getting this into some sort of class that would be great too.



var gridHolder = document.getElementById("gridHolder"),
gridAnchor = document.getElementById("gridAnchor"),
grid = document.getElementById('grid'),
staging = document.getElementById("staging"),
showCount = 0,
currentTarget,
currentTargetRect,
origin = gridAnchor.getBoundingClientRect(),
dx, dy,
intervals = 12,
blockHeight = 44,
blockWidth = 144,
blockIntervalWidth = blockWidth / intervals,
intervalValue = 60 / intervals,
monday = new Date(),
gridDays = document.createElement('div'),
gridDaysWidth = 100,
gridTimes = document.createElement('div'),
gridTimesHeight = 24,
days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

gridHolder.addEventListener("mousedown", selectBlock);
document.getElementById("addShow").addEventListener("click", addShow);

monday.setHours(-((monday.getDay() - 1) * 24), 0, 0, 0);

gridDays.className = "grid-days";
gridDays.style.width = gridDaysWidth;
gridTimes.className = "grid-times";
gridTimes.style.height = gridTimesHeight;

grid.style.marginLeft = gridDaysWidth;

for (var i = 0; i bounds.left && currentTargetBounds.top > bounds.top && currentTargetBounds.bottom
div {
box-sizing: border-box;
}
.wrapper {
padding: 10px;
}
.grid-holder {
display: inline-block;
width: 4000px;
}
.grid-anchor

Solution

There is a lot of code so I can not address every aspect of your code.
First impression.

It works, just, but is very unfriendly.
Cursors

Cursors are a must when doing any form of mouse interaction. When over a draggable item the cursor should be "grab" and then to "grabbing" or "none" when dragging. The CSS standard cursor set is very limited, learn how to create your own cursors and use them. I can not overstate how important cursors are to good UI design. They are the forgotten information provider in may apps.
Select drag!

One thing I find it very annoying, even professional sites seem to miss this, Turn off "select drag" when mouse is over draggable items. CSS rule user-select: none; and appropriate prefixes if needed. It just looks horrible when a big blue area is selected just for dragging something.
Smarter drop

Don't allow dropped items to overlap. Move the dropped item to fit in front of or behind items under it. If you drop over an item and there is another after insert the new item after the current and move the next one to give room.

Snap to the day the mouse is over (if showing it) or to the day nearest the center of the control.
Scale

Use the mouse wheel input to scale in and out (if not over item). The current screen is way to wide. You may also allow that when the mouse is over an item that the mouse wheel moves it left and right. (with appropriate cursor)
Bits and bobs

  • Fade the dragged item so you can see what is under.



  • It seems to hold the item sometimes even with the mouse button up.



  • Provide a clear disposal icon to allow the item to be removed. Drag block over dispose icon to remove.



  • Allow a modifier for creating a copy. Eg [ctrl] drag or Right click drag to copy.



I noticed a comment about touch devices. DONT try and code a touch interface and mouse interface on the same page. Detect the interface and load the appropriate interface

Also someone suggested using a pre existing library. Javascript libraries I find to be very poor quality. If you do use one, befor you do, look at the source code, look at the documentation. If you find the code hard to read and the documentation sparse then don't use it. Just because a lib has a lot of stars (what not) does not make it a good lib. I see more time wasted wrangling inappropriate, overly complex, or just plain unfinished and buggy libs than would have ever been spent creating the functionality you need yourself.
The Code
Style!

Before you write another line of code read Airbnb JavaScript Style Guide. Once you have read it, read it again in a week, and agian in a month. Learn it inside out. Style is the most important aspect of coding in any language. Bad and inconsistent style is the leading cause of bugs in all languages.

I personal do not agree with all the style guidelines in the document, but I have sound and good reason for why. If you can not find reason not to adopt a style in the document then do as the document says. The benefits will show as soon as you start coding to the consistent style.

That takes care of style and I will address the code design.
Code design

The code is all over the place, just a sea of seemingly unrelated functions intermixed with the odd bit of immediate functionality. This is very hard to manage as the code base grows. Break the application up into smaller and related parts.

I was going to add "data does not belong in code" but I see you have commented out the AJAX fetches. Still for experimenting you should still use data external to any of the code.
Abstractions and modular design.

Your app is mixing core functionality, information , UI and rendering. These things should exist independently of each other. What is the core of the app (to schedule radio shows) It should be able to do all the things that a scheduler is expected to do independently of any UI or Display. It does this via an interface to some core abstract types.

You need to design some objects that together create the core functionality of the app.

What follows is only a suggestion and not at all an in depth analysis of your application. These are only to give example of how modules may relate and communicate.

Some suggested abstract objects. Timeline, Show.

Some related functionality. Timeline.addShow, Timeline.removeShow, Timeline.nextShowTime, Timeline.rescedualShow, Timeline.isTimeFree, Timeline.showAtTime, etc...

Show.setName, Show.getLength, Show.hasPlayed, 'Show.getId' etc...

Having the information you are managing separate from the display will make the task of displaying that information a lot easier.
Renderer and UI

A renderer interrogates the Timeline and Show interfaces to workout what to display and where.

A UI interface that is strongly tied to the render and is a middle man between the renderer and the Timeline, Show interfaces.

Remember the actual functionality of your app, to schedule play times must be able to function independently of a front end.
Example of mod

Context

StackExchange Code Review Q#152543, answer score: 3

Revisions (0)

No revisions yet.