private void animate() {
            graphics.clearRect(0, 0, canvasWidth, canvasHeight);
            drawLabel.repaint();

            // first, calculate the total length of line segments and turns,
            // in order to allocate drawtime proportionally later

            double totalLength = 0;
            for (Action a : actionList) {
                if (a.type == ActionType.TURN) {
                    totalLength += LENGTH_OF_A_TURN;
                } else if (a.type == ActionType.FORWARD) {
                    totalLength += a.lineSeg.length();
                }
            }

            // now, draw the animation

            double cumulativeLength = 0;
            long initialTime = System.currentTimeMillis();
            for (int i = 0; i < actionListSize; i++) {
                if (isCancelled()) {
                    break;
                }
                Action action = actionList.get(i);
                setCurrentAction((i + 1) + ". " + action);
                if (action.lineSeg != null) {
                    long startTime = (long) (initialTime + cumulativeLength / totalLength * MILLIS_PER_DRAWING);
                    cumulativeLength += action.lineSeg.length();
                    long endTime = (long) (initialTime + cumulativeLength / totalLength * MILLIS_PER_DRAWING);
                    draw(action.lineSeg, startTime, endTime);
                } else {
                    cumulativeLength += LENGTH_OF_A_TURN;
                    long drawTime = (long) (initialTime + cumulativeLength / totalLength * MILLIS_PER_DRAWING - System.currentTimeMillis());
                    if (drawTime > 0) {
                        try {
                            Thread.sleep((long) drawTime);
                        } catch (InterruptedException e) {
                        }
                    }
                }
            }
            stopAnimation();
        }