diff --git a/app/controllers/gantts_controller.rb b/app/controllers/gantts_controller.rb
index 6d2c26128..3e7db9c73 100644
--- a/app/controllers/gantts_controller.rb
+++ b/app/controllers/gantts_controller.rb
@@ -19,7 +19,7 @@
 
 class GanttsController < ApplicationController
   menu_item :gantt
-  before_action :find_optional_project
+  before_action :find_optional_project, :only => [:show]
 
   rescue_from Query::StatementInvalid, :with => :query_statement_invalid
 
@@ -55,4 +55,25 @@ class GanttsController < ApplicationController
       end
     end
   end
+
+  def change_duration
+    return render_error(:status => :unprocessable_entity) unless request.xhr?
+
+    @obj = Issue.find(params[:id])
+    raise Unauthorized unless @obj.visible?
+
+    ActiveRecord::Base.transaction do
+      @obj.init_journal(User.current)
+      @obj.safe_attributes = params[:change_duration]
+      if !@obj.save
+        render_403(:message => @obj.errors.full_messages.join)
+        raise ActiveRecord::Rollback
+      end
+    end
+    retrieve_query
+  rescue ActiveRecord::StaleObjectError
+    render_403(:message => :notice_issue_update_conflict)
+  rescue ActiveRecord::RecordNotFound
+    render_404
+  end
 end
diff --git a/app/views/gantts/change_duration.js.erb b/app/views/gantts/change_duration.js.erb
new file mode 100644
index 000000000..113ee8c46
--- /dev/null
+++ b/app/views/gantts/change_duration.js.erb
@@ -0,0 +1,81 @@
+<%
+@draw_objs = []
+
+def select_precedes(issue)
+  issue.relations_from.where(:relation_type => IssueRelation::TYPE_PRECEDES).map(&:issue_to).each do |follows|
+    next if @draw_objs.include?(follows)
+
+    while follows do
+      @draw_objs.concat [follows, follows.fixed_version, follows.project]
+      select_precedes(follows)
+      follows.children.each do |child|
+        @draw_objs.concat [child, child.fixed_version, child.project]
+        select_precedes(child)
+      end
+      follows = follows.parent
+    end
+  end
+end
+
+issue = @obj
+while issue do
+  @draw_objs.concat [issue, issue.fixed_version, issue.project]
+  select_precedes(issue)
+  issue = issue.parent
+end
+@draw_objs = @draw_objs.compact.uniq
+@draw_objs.reject!{|obj| ![Project, Version, Issue].include?(obj.class)}
+-%>
+var elm;
+<%
+gantt = Redmine::Helpers::Gantt.new(params)
+gantt.view = self
+gantt.query = @query
+
+@draw_objs.each do |obj|
+  gantt.instance_variable_set(:@number_of_rows, 0)
+  gantt.instance_variable_set(:@lines, '')
+  gantt.render_object_row(
+    obj,
+    {format: :html, only: :lines, zoom: 2 ** gantt.zoom, top: 0, top_increment: 20}
+  )
+  todo_content = Nokogiri::HTML.parse(gantt.instance_variable_get(:@lines))
+  todo_content = todo_content.xpath(
+    "//div[contains(@class,'task') and contains(@class,'line')]/*"
+  ).to_s.tr("\n",'').gsub(/'/, "\\\\'")
+
+  klass_name = obj.class.name.underscore
+  elm_todo = "[id=task-todo-#{klass_name}-#{obj.id}]"
+  css_subject = 'span:not(.expander)'
+  elm_subject = raw("[id=#{klass_name}-#{obj.id}] > #{css_subject}")
+
+  subject_content = Nokogiri::HTML.parse(gantt.__send__(:html_subject_content, obj))
+  subject_content = subject_content.css(css_subject).to_s.tr("\n",'').gsub(/'/, "\\\\'")
+-%>
+if($('<%= elm_subject %>').length){
+  $('<%= elm_todo %>').each(function(_, task) {
+    var el_parent = $(task).parent();
+    el_parent.html('<%= raw(todo_content) %>');
+    var number_of_rows = el_parent.attr('data-number-of-rows');
+    if(number_of_rows){
+      el_parent.find('div[data-number-of-rows]').attr('data-number-of-rows', number_of_rows);
+    }
+  });
+  $('<%= elm_subject %>').replaceWith('<%= raw(subject_content) %>');
+<%
+  case obj
+  when Issue
+    @query.columns.each do |column|
+-%>
+  elm = $('div.gantt_selected_column_content #<%= column.name %>_issue_<%= obj.id %>');
+  if(elm.length){
+    elm.html('<%= escape_javascript(column_content(column, obj)) %>');
+  }
+<%
+    end
+  end
+-%>
+}
+<%
+end
+-%>
diff --git a/config/routes.rb b/config/routes.rb
index acc3ca465..fb619a817 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -60,6 +60,7 @@ Rails.application.routes.draw do
 
   get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt'
   get '/issues/gantt', :to => 'gantts#show'
+  put '/gantt/:id/change_duration', :to => 'gantts#change_duration', :as => 'gantt_change_duration'
 
   get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
   get '/issues/calendar', :to => 'calendars#show'
diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb
index 9b68f32c2..d9f25fc05 100644
--- a/lib/redmine/helpers/gantt.rb
+++ b/lib/redmine/helpers/gantt.rb
@@ -347,6 +347,7 @@ module Redmine
         if options[:format] == :html
           data_options = {}
           data_options[:collapse_expand] = "issue-#{issue.id}"
+          data_options[:number_of_rows] = number_of_rows
           style = "position: absolute;top: #{options[:top]}px; font-size: 0.8em;"
           content =
             view.content_tag(
@@ -771,6 +772,7 @@ module Redmine
           tag_options[:class] = "version-name"
           has_children = object.fixed_issues.exists?
         when Project
+          tag_options[:id] = "project-#{object.id}"
           tag_options[:class] = "project-name"
           has_children = object.issues.exists? || object.versions.exists?
         end
@@ -780,6 +782,7 @@ module Redmine
               :top_increment => params[:top_increment],
               :obj_id => "#{object.class}-#{object.id}".downcase,
             },
+            :number_of_rows => number_of_rows,
           }
         end
         if has_children
@@ -835,7 +838,10 @@ module Redmine
       def html_task(params, coords, markers, label, object)
         output = +''
         data_options = {}
-        data_options[:collapse_expand] = "#{object.class}-#{object.id}".downcase if object
+        if object
+          data_options[:collapse_expand] = "#{object.class}-#{object.id}".downcase
+          data_options[:number_of_rows] = number_of_rows
+        end
         css = "task " +
           case object
           when Project
@@ -849,15 +855,21 @@ module Redmine
           end
         # Renders the task bar, with progress and late
         if coords[:bar_start] && coords[:bar_end]
-          width = coords[:bar_end] - coords[:bar_start] - 2
+          width = coords[:bar_end] - coords[:bar_start]
           style = +""
-          style << "top:#{params[:top]}px;"
           style << "left:#{coords[:bar_start]}px;"
           style << "width:#{width}px;"
-          html_id = "task-todo-issue-#{object.id}" if object.is_a?(Issue)
-          html_id = "task-todo-version-#{object.id}" if object.is_a?(Version)
+          html_id =
+            case object
+            when Project
+              "task-todo-project-#{object.id}"
+            when Version
+              "task-todo-version-#{object.id}"
+            when Issue
+              "task-todo-issue-#{object.id}"
+            end
           content_opt = {:style => style,
-                         :class => "#{css} task_todo",
+                         :class => "task_todo",
                          :id => html_id,
                          :data => {}}
           if object.is_a?(Issue)
@@ -865,32 +877,78 @@ module Redmine
             if rels.present?
               content_opt[:data] = {"rels" => rels.to_json}
             end
+            content_opt[:data].merge!({
+              :url_change_duration => Rails.application.routes.url_helpers.gantt_change_duration_path(
+                object
+              ),
+              :object => {
+                :start_date => object.start_date,
+                :due_date => object.due_date,
+                :lock_version => object.lock_version,
+              }.to_json,
+            })
           end
           content_opt[:data].merge!(data_options)
-          output << view.content_tag(:div, '&nbsp;'.html_safe, content_opt)
+          bar_contents = []
           if coords[:bar_late_end]
-            width = coords[:bar_late_end] - coords[:bar_start] - 2
+            width = coords[:bar_late_end] - coords[:bar_start]
             style = +""
-            style << "top:#{params[:top]}px;"
-            style << "left:#{coords[:bar_start]}px;"
             style << "width:#{width}px;"
-            output << view.content_tag(:div, '&nbsp;'.html_safe,
-                                       :style => style,
-                                       :class => "#{css} task_late",
-                                       :data => data_options)
+            bar_contents << view.content_tag(:div, '&nbsp;'.html_safe,
+                                             :style => style,
+                                             :class => "task_late",
+                                             :data => data_options)
           end
           if coords[:bar_progress_end]
-            width = coords[:bar_progress_end] - coords[:bar_start] - 2
+            width = coords[:bar_progress_end] - coords[:bar_start]
             style = +""
-            style << "top:#{params[:top]}px;"
-            style << "left:#{coords[:bar_start]}px;"
             style << "width:#{width}px;"
             html_id = "task-done-issue-#{object.id}" if object.is_a?(Issue)
             html_id = "task-done-version-#{object.id}" if object.is_a?(Version)
-            output << view.content_tag(:div, '&nbsp;'.html_safe,
+            bar_contents << view.content_tag(:div, '&nbsp;'.html_safe,
+                                             :style => style,
+                                             :class => "task_done",
+                                             :id => html_id,
+                                             :data => data_options)
+          end
+
+          # Renders the tooltip
+          if object.is_a?(Issue)
+            s = view.content_tag(:span,
+                               view.render_issue_tooltip(object).html_safe,
+                               :class => "tip")
+            s += view.content_tag(:input, nil, :type => 'checkbox', :name => 'ids[]', :value => object.id, :style => 'display:none;', :class => 'toggle-selection')
+            style = +""
+            style << "width:#{coords[:bar_end] - coords[:bar_start]}px;"
+            style << "height:12px;"
+            bar_contents << view.content_tag(:div, s.html_safe,
+                                             :style => style,
+                                             :class => "tooltip hascontextmenu",
+                                             :data => data_options)
+          end
+
+          # Renders the label on the right
+          if label
+            style = +""
+            style << "top:0px;"
+            style << "left:#{coords[:bar_end] - coords[:bar_start] + 8}px;"
+            bar_contents << view.content_tag(:div, label,
+                                             :style => style,
+                                             :class => "label",
+                                             :data => data_options)
+          end
+
+          bar_contents = bar_contents.join.presence
+          output << view.content_tag(:div, (bar_contents || '&nbsp;').html_safe, content_opt)
+        else
+          # Renders the label on the right
+          if label
+            style = +""
+            style << "top:1px;"
+            style << "left:#{(coords[:bar_end] || 0) + 8}px;"
+            output << view.content_tag(:div, label,
                                        :style => style,
-                                       :class => "#{css} task_done",
-                                       :id => html_id,
+                                       :class => "label",
                                        :data => data_options)
           end
         end
@@ -898,55 +956,26 @@ module Redmine
         if markers
           if coords[:start]
             style = +""
-            style << "top:#{params[:top]}px;"
             style << "left:#{coords[:start]}px;"
-            style << "width:15px;"
             output << view.content_tag(:div, '&nbsp;'.html_safe,
                                        :style => style,
-                                       :class => "#{css} marker starting",
+                                       :class => "marker starting",
                                        :data => data_options)
           end
           if coords[:end]
             style = +""
-            style << "top:#{params[:top]}px;"
             style << "left:#{coords[:end]}px;"
-            style << "width:15px;"
             output << view.content_tag(:div, '&nbsp;'.html_safe,
                                        :style => style,
-                                       :class => "#{css} marker ending",
+                                       :class => "marker ending",
                                        :data => data_options)
           end
         end
-        # Renders the label on the right
-        if label
-          style = +""
-          style << "top:#{params[:top]}px;"
-          style << "left:#{(coords[:bar_end] || 0) + 8}px;"
-          style << "width:15px;"
-          output << view.content_tag(:div, label,
-                                     :style => style,
-                                     :class => "#{css} label",
-                                     :data => data_options)
-        end
-        # Renders the tooltip
-        if object.is_a?(Issue) && coords[:bar_start] && coords[:bar_end]
-          s = view.content_tag(:span,
-                               view.render_issue_tooltip(object).html_safe,
-                               :class => "tip")
-          s += view.content_tag(:input, nil, :type => 'checkbox', :name => 'ids[]',
-                                :value => object.id, :style => 'display:none;',
-                                :class => 'toggle-selection')
-          style = +""
-          style << "position: absolute;"
-          style << "top:#{params[:top]}px;"
-          style << "left:#{coords[:bar_start]}px;"
-          style << "width:#{coords[:bar_end] - coords[:bar_start]}px;"
-          style << "height:12px;"
-          output << view.content_tag(:div, s.html_safe,
-                                     :style => style,
-                                     :class => "tooltip hascontextmenu",
-                                     :data => data_options)
-        end
+        output = view.content_tag(:div, output.html_safe,
+          :class => "#{css} line",
+          :style => "top:#{params[:top]}px;width:#{params[:g_width] - 1}px;",
+          :data => data_options
+        )
         @lines << output
         output
       end
diff --git a/public/images/milestone_done.png b/public/images/milestone_done.png
deleted file mode 100644
index 5fdcb415c..000000000
Binary files a/public/images/milestone_done.png and /dev/null differ
diff --git a/public/images/milestone_late.png b/public/images/milestone_late.png
deleted file mode 100644
index cf922e954..000000000
Binary files a/public/images/milestone_late.png and /dev/null differ
diff --git a/public/images/milestone_todo.png b/public/images/milestone_todo.png
deleted file mode 100644
index 4c051c857..000000000
Binary files a/public/images/milestone_todo.png and /dev/null differ
diff --git a/public/images/project_marker.png b/public/images/project_marker.png
deleted file mode 100644
index 4124787d0..000000000
Binary files a/public/images/project_marker.png and /dev/null differ
diff --git a/public/images/task_done.png b/public/images/task_done.png
deleted file mode 100644
index 5fdcb415c..000000000
Binary files a/public/images/task_done.png and /dev/null differ
diff --git a/public/images/task_late.png b/public/images/task_late.png
deleted file mode 100644
index 71fd2d70b..000000000
Binary files a/public/images/task_late.png and /dev/null differ
diff --git a/public/images/task_parent_end.png b/public/images/task_parent_end.png
deleted file mode 100644
index 9442b86a5..000000000
Binary files a/public/images/task_parent_end.png and /dev/null differ
diff --git a/public/images/task_todo.png b/public/images/task_todo.png
deleted file mode 100644
index 632406ee1..000000000
Binary files a/public/images/task_todo.png and /dev/null differ
diff --git a/public/images/version_marker.png b/public/images/version_marker.png
deleted file mode 100644
index 0368ca290..000000000
Binary files a/public/images/version_marker.png and /dev/null differ
diff --git a/public/javascripts/gantt.js b/public/javascripts/gantt.js
index da3b86b7a..d78da372a 100644
--- a/public/javascripts/gantt.js
+++ b/public/javascripts/gantt.js
@@ -4,14 +4,12 @@
 var draw_gantt = null;
 var draw_top;
 var draw_right;
-var draw_left;
 
 var rels_stroke_width = 2;
 
 function setDrawArea() {
-  draw_top   = $("#gantt_draw_area").position().top;
+  draw_top   = $("#gantt_draw_area").offset().top;
   draw_right = $("#gantt_draw_area").width();
-  draw_left  = $("#gantt_area").scrollLeft();
 }
 
 function getRelationsArray() {
@@ -42,27 +40,27 @@ function drawRelations() {
       return;
     }
     var issue_height = issue_from.height();
-    var issue_from_top   = issue_from.position().top  + (issue_height / 2) - draw_top;
+    var issue_from_top   = issue_from.offset().top  + (issue_height / 2) - draw_top;
     var issue_from_right = issue_from.position().left + issue_from.width();
-    var issue_to_top   = issue_to.position().top  + (issue_height / 2) - draw_top;
+    var issue_to_top   = issue_to.offset().top  + (issue_height / 2) - draw_top;
     var issue_to_left  = issue_to.position().left;
     var color = issue_relation_type[element_issue["rel_type"]]["color"];
     var landscape_margin = issue_relation_type[element_issue["rel_type"]]["landscape_margin"];
     var issue_from_right_rel = issue_from_right + landscape_margin;
     var issue_to_left_rel    = issue_to_left    - landscape_margin;
-    draw_gantt.path(["M", issue_from_right + draw_left,     issue_from_top,
-                     "L", issue_from_right_rel + draw_left, issue_from_top])
+    draw_gantt.path(["M", issue_from_right,     issue_from_top,
+                     "L", issue_from_right_rel, issue_from_top])
                    .attr({stroke: color,
                           "stroke-width": rels_stroke_width
                           });
     if (issue_from_right_rel < issue_to_left_rel) {
-      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
-                       "L", issue_from_right_rel + draw_left, issue_to_top])
+      draw_gantt.path(["M", issue_from_right_rel, issue_from_top,
+                       "L", issue_from_right_rel, issue_to_top])
                      .attr({stroke: color,
                           "stroke-width": rels_stroke_width
                           });
-      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_to_top,
-                       "L", issue_to_left + draw_left,        issue_to_top])
+      draw_gantt.path(["M", issue_from_right_rel, issue_to_top,
+                       "L", issue_to_left,        issue_to_top])
                      .attr({stroke: color,
                           "stroke-width": rels_stroke_width
                           });
@@ -70,28 +68,28 @@ function drawRelations() {
       var issue_middle_top = issue_to_top +
                                 (issue_height *
                                    ((issue_from_top > issue_to_top) ? 1 : -1));
-      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
-                       "L", issue_from_right_rel + draw_left, issue_middle_top])
+      draw_gantt.path(["M", issue_from_right_rel, issue_from_top,
+                       "L", issue_from_right_rel, issue_middle_top])
                      .attr({stroke: color,
                           "stroke-width": rels_stroke_width
                           });
-      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_middle_top,
-                       "L", issue_to_left_rel + draw_left,    issue_middle_top])
+      draw_gantt.path(["M", issue_from_right_rel, issue_middle_top,
+                       "L", issue_to_left_rel,    issue_middle_top])
                      .attr({stroke: color,
                           "stroke-width": rels_stroke_width
                           });
-      draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_middle_top,
-                       "L", issue_to_left_rel + draw_left, issue_to_top])
+      draw_gantt.path(["M", issue_to_left_rel, issue_middle_top,
+                       "L", issue_to_left_rel, issue_to_top])
                      .attr({stroke: color,
                           "stroke-width": rels_stroke_width
                           });
-      draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_to_top,
-                       "L", issue_to_left + draw_left,     issue_to_top])
+      draw_gantt.path(["M", issue_to_left_rel, issue_to_top,
+                       "L", issue_to_left,     issue_to_top])
                      .attr({stroke: color,
                           "stroke-width": rels_stroke_width
                           });
     }
-    draw_gantt.path(["M", issue_to_left + draw_left, issue_to_top,
+    draw_gantt.path(["M", issue_to_left, issue_to_top,
                      "l", -4 * rels_stroke_width, -2 * rels_stroke_width,
                      "l", 0, 4 * rels_stroke_width, "z"])
                    .attr({stroke: "none",
@@ -104,11 +102,11 @@ function drawRelations() {
 
 function getProgressLinesArray() {
   var arr = new Array();
-  var today_left = $('#today_line').position().left;
+  var today_left = $('#today_line').position().left + $("#gantt_area").scrollLeft();
   arr.push({left: today_left, top: 0});
   $.each($('div.issue-subject, div.version-name'), function(index, element) {
     if(!$(element).is(':visible')) return true;
-    var t = $(element).position().top - draw_top ;
+    var t = $(element).offset().top - draw_top ;
     var h = ($(element).height() / 9);
     var element_top_upper  = t - h;
     var element_top_center = t + (h * 3);
@@ -125,8 +123,11 @@ function getProgressLinesArray() {
         arr.push({left: draw_right, top: element_top_upper, is_right_edge: true});
         arr.push({left: draw_right, top: element_top_lower, is_right_edge: true, none_stroke: true});
       } else if (issue_done.length > 0) {
-        var done_left = issue_done.first().position().left +
-                           issue_done.first().width();
+        var done_left = today_left;
+        var issue_todo = $("#task-todo-" + $(element).attr("id"));
+        if (issue_todo.length > 0){
+          done_left = issue_todo.first().position().left;
+        }
         arr.push({left: done_left, top: element_top_center});
       } else if (is_behind_start) {
         arr.push({left: 0 , top: element_top_upper, is_left_edge: true});
@@ -145,6 +146,7 @@ function getProgressLinesArray() {
 }
 
 function drawGanttProgressLines() {
+  if(!$("#today_line").length) return;
   var arr = getProgressLinesArray();
   var color = $("#today_line")
                     .css("border-left-color");
@@ -154,8 +156,8 @@ function drawGanttProgressLines() {
         (!("is_right_edge" in arr[i - 1] && "is_right_edge" in arr[i]) &&
          !("is_left_edge"  in arr[i - 1] && "is_left_edge"  in arr[i]))
         ) {
-      var x1 = (arr[i - 1].left == 0) ? 0 : arr[i - 1].left + draw_left;
-      var x2 = (arr[i].left == 0)     ? 0 : arr[i].left     + draw_left;
+      var x1 = (arr[i - 1].left == 0) ? 0 : arr[i - 1].left;
+      var x2 = (arr[i].left == 0)     ? 0 : arr[i].left;
       draw_gantt.path(["M", x1, arr[i - 1].top,
                        "L", x2, arr[i].top])
                    .attr({stroke: color, "stroke-width": 2});
@@ -253,13 +255,16 @@ ganttEntryClick = function(e){
   subject.nextAll('div').each(function(_, element){
     var el = $(element);
     var json = el.data('collapse-expand');
+    var number_of_rows = el.data('number-of-rows');
+    var el_task_bars = '#gantt_area form > div[data-collapse-expand="' + json.obj_id + '"][data-number-of-rows="' + number_of_rows + '"]';
+    var el_selected_columns = 'td.gantt_selected_column div[data-collapse-expand="' + json.obj_id + '"][data-number-of-rows="' + number_of_rows + '"]';
     if(out_of_hierarchy || parseInt(el.css('left')) <= subject_left){
       out_of_hierarchy = true;
       if(target_shown == null) return false;
 
       var new_top_val = parseInt(el.css('top')) + total_height * (target_shown ? -1 : 1);
       el.css('top', new_top_val);
-      $('#gantt_area form > div[data-collapse-expand="' + json.obj_id + '"], td.gantt_selected_column div[data-collapse-expand="' + json.obj_id + '"]').each(function(_, el){
+      $([el_task_bars, el_selected_columns].join()).each(function(_, el){
         $(el).css('top', new_top_val);
       });
       return true;
@@ -272,15 +277,14 @@ ganttEntryClick = function(e){
       total_height = 0;
     }
     if(is_shown == target_shown){
-      $('#gantt_area form > div[data-collapse-expand="' + json.obj_id + '"]').each(function(_, task) {
+      $(el_task_bars).each(function(_, task) {
         var el_task = $(task);
         if(!is_shown)
           el_task.css('top', target_top + total_height);
         if(!el_task.hasClass('tooltip'))
           el_task.toggle(!is_shown);
       });
-      $('td.gantt_selected_column div[data-collapse-expand="' + json.obj_id + '"]'
-          ).each(function (_, attr) {
+      $(el_selected_columns).each(function (_, attr) {
         var el_attr = $(attr);
         if (!is_shown)
           el_attr.css('top', target_top + total_height);
@@ -301,3 +305,110 @@ function disable_unavailable_columns(unavailable_columns) {
     $('#available_c, #selected_c').children("[value='" + value + "']").prop('disabled', true);
   });
 }
+
+initGanttDnD = function(){
+  var grid_x = 0;
+  if($('#zoom').length){
+    switch(parseInt($('#zoom').val())){
+    case 4:
+      grid_x = 16;
+      break;
+    case 3:
+      grid_x = 8;
+      break;
+    }
+  }
+  if(grid_x > 0){
+    $('.leaf .task_todo').draggable({
+      containment: 'parent',
+      axis: 'x',
+      grid: [grid_x, 0],
+      opacity: 0.5,
+      cursor: 'move',
+      revertDuration: 100,
+      start: function (event, ui) {
+        var helper = ui.helper[0];
+        helper.startLeft = ui.position.left;
+      },
+    });
+
+    $('.task.line').droppable({
+      accept: '.leaf .task_todo',
+      drop: function (event, ui) {
+        var target = $(ui.draggable);
+        var url = target.attr('data-url-change-duration');
+        var object = JSON.parse(target.attr('data-object'));
+        var startLeft = target[0].startLeft;
+        var relative_days = Math.floor((ui.position.left - startLeft) / grid_x);
+        if(relative_days == 0){
+          return;
+        }
+        var start_date = new Date(object.start_date);
+        start_date.setDate(start_date.getDate() + relative_days);
+        start_date =
+          [
+            start_date.getFullYear(),
+            ('0' + (start_date.getMonth() + 1)).slice(-2),
+            ('0' + start_date.getDate()).slice(-2),
+          ].join('-');
+        var due_date = null;
+        if(object.due_date != null){
+          due_date = new Date(object.due_date);
+          due_date.setDate(due_date.getDate() + relative_days);
+          due_date =
+            [
+              due_date.getFullYear(),
+              ('0' + (due_date.getMonth() + 1)).slice(-2),
+              ('0' + due_date.getDate()).slice(-2),
+            ].join('-');
+        }
+
+        $('#selected_c option:not(:disabled)').prop('selected', true);
+        var form = $('#query_form').serializeArray();
+        var json_param = {};
+        form.forEach(function(data){
+          var key = data.name;
+          var value = data.value;
+          if(/\[\]$/.test(key)){
+            if(!json_param.hasOwnProperty(key)){
+              json_param[key] = [];
+            }
+            json_param[key].push(value);
+          }
+          else{
+            json_param[key] = value;
+          }
+        });
+        $('#selected_c option:not(:disabled)').prop('selected', false);
+        Object.assign(json_param, {
+          change_duration: {
+            start_date: start_date,
+            due_date: due_date,
+            lock_version: object.lock_version,
+          },
+        });
+
+        $.ajax({
+          type: 'PUT',
+          url: url,
+          data: json_param,
+        }).done(function(data){
+          drawGanttHandler();
+          initGanttDnD();
+        }).fail(function(jqXHR){
+          var contents = $('<div>' + jqXHR.responseText + '</div>');
+          var error_message = contents.find('p#errorExplanation');
+          if(error_message.length){
+            $('div#content h2:first-of-type').after(error_message);
+            $('p#errorExplanation').hide('fade', {}, 3000, function(){
+              $(this).remove();
+            });
+          }
+          ui.draggable.animate({'left': ui.draggable[0].startLeft}, 'fast');
+        });
+      }
+    });
+  }
+};
+
+$(document).ready(initGanttDnD);
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 1c2f76c15..95b0b02bd 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -1410,7 +1410,7 @@ td.gantt_selected_column .gantt_hdr,.gantt_selected_column_container {
 
 .task {
   position: absolute;
-  height:8px;
+  height:10px;
   font-size:0.8em;
   color:#888;
   padding:0;
@@ -1419,27 +1419,87 @@ td.gantt_selected_column .gantt_hdr,.gantt_selected_column_container {
   white-space:nowrap;
 }
 
-.task.label {width:100%;}
-.task.label.project, .task.label.version { font-weight: bold; }
+.task.line { left: 0; }
+.task div.tooltip:hover span.tip { font-size: inherit; }
+.task .task_todo .label { font-size: inherit; }
+.task.project .task_todo .label { margin-top: -4px; }
+.task.version .task_todo .label { margin-top: -3px; }
 
-.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
-.task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; }
-.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
+.task .label { position: absolute; width: auto; }
+.task.project .label, .task.version .label { font-weight: bold; }
 
-.task_todo.parent { background: #888; border: 1px solid #888; height: 3px;}
-.task_late.parent, .task_done.parent { height: 3px;}
-.task.parent.marker.starting  { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;}
-.task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;}
+.task_late { position: absolute; height: inherit; background:#f66; }
+.task_done { position: absolute; height: inherit; background:#00c600; }
+.task_todo { position: absolute; height: inherit; background:#aaa; }
 
-.version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
-.version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
-.version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
-.version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
+.parent .task_todo { background: #888; height: 5px; }
+.parent .task_late, .parent .task_done { height: 5px; }
+.parent .marker {
+  background: #888;
+  display: inline-block;
+  position: absolute;
+  width: 8px;
+  height: 6px;
+  margin-left: -5px;
+  margin-bottom: -4px;
+}
+.parent .marker:after {
+  border-top: 3px solid #888;
+  border-left: 4px solid transparent;
+  border-right: 4px solid transparent;
+  content: '';
+  height: 0;
+  left: 0;
+  position: absolute;
+  bottom: -3px;
+  width: 0;
+}
+
+.version .task_late { background:#f66; height: 4px; }
+.version .task_done { background:#00c600; height: 4px; }
+.version .task_todo { background:#aaa; height: 4px; margin-top: 3px; }
+.version .marker {
+  width: 0;
+  height: 0;
+  border: 5px solid transparent;
+  border-bottom-color: black;
+  position: absolute;
+  margin-top: -5px;
+  margin-left: -6px;
+}
+.version .marker:after {
+  content: '';
+  position: absolute;
+  left: -5px;
+  top: 5px;
+  width: 0;
+  height: 0;
+  border: 5px solid transparent;
+  border-top-color: black;
+}
 
-.project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;}
-.project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;}
-.project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;}
-.project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; }
+.project .task_late { background:#f66; height: 2px; }
+.project .task_done { background:#00c600; height: 2px; }
+.project .task_todo { background:#aaa; height: 2px; margin-top: 4px; }
+.project .marker {
+  width: 0;
+  height: 0;
+  border: 5px solid transparent;
+  border-bottom-color: blue;
+  position: absolute;
+  margin-top: -5px;
+  margin-left: -6px;
+}
+.project .marker:after {
+  content: '';
+  position: absolute;
+  left: -5px;
+  top: 5px;
+  width: 0;
+  height: 0;
+  border: 5px solid transparent;
+  border-top-color: blue;
+}
 
 .version-behind-schedule a, .issue-behind-schedule a {color: #f66914;}
 .version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;}
diff --git a/test/integration/routing/gantts_test.rb b/test/integration/routing/gantts_test.rb
index 4e859c77d..29384c59a 100644
--- a/test/integration/routing/gantts_test.rb
+++ b/test/integration/routing/gantts_test.rb
@@ -26,5 +26,7 @@ class RoutingGanttsTest < Redmine::RoutingTest
 
     should_route 'GET /projects/foo/issues/gantt' => 'gantts#show', :project_id => 'foo'
     should_route 'GET /projects/foo/issues/gantt.pdf' => 'gantts#show', :project_id => 'foo', :format => 'pdf'
+
+    should_route 'PUT /gantt/123/change_duration' => 'gantts#change_duration', :id => '123'
   end
 end
diff --git a/test/unit/lib/redmine/helpers/gantt_test.rb b/test/unit/lib/redmine/helpers/gantt_test.rb
index 22d02f164..7e3b31d76 100644
--- a/test/unit/lib/redmine/helpers/gantt_test.rb
+++ b/test/unit/lib/redmine/helpers/gantt_test.rb
@@ -235,19 +235,28 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest
     @project.issues << @issue
     @output_buffer = @gantt.lines
 
-    assert_select "div.project.task_todo"
-    assert_select "div.project.starting"
-    assert_select "div.project.ending"
-    assert_select "div.label.project", /#{@project.name}/
+    assert_select "div.task.project" do
+      assert_select "> div.task_todo" do
+        assert_select "> div.label", /#{@project.name}/
+      end
+      assert_select "> div.starting"
+      assert_select "> div.ending"
+    end
 
-    assert_select "div.version.task_todo"
-    assert_select "div.version.starting"
-    assert_select "div.version.ending"
-    assert_select "div.label.version", /#{@version.name}/
+    assert_select "div.task.version" do
+      assert_select "> div.task_todo" do
+        assert_select "div.label", /#{@version.name}/
+      end
+      assert_select "> div.starting"
+      assert_select "> div.ending"
+    end
 
-    assert_select "div.task_todo"
-    assert_select "div.task.label", /#{@issue.done_ratio}/
-    assert_select "div.tooltip", /#{@issue.subject}/
+    assert_select "div.task" do
+      assert_select "> div.task_todo" do
+        assert_select "> div.label", /#{@issue.done_ratio}/
+        assert_select "> div.tooltip", /#{@issue.subject}/
+      end
+    end
   end
 
   test "#selected_column_content" do
@@ -331,7 +340,9 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest
     @project.stubs(:start_date).returns(today - 7)
     @project.stubs(:due_date).returns(today + 7)
     @output_buffer = @gantt.line_for_project(@project, :format => :html)
-    assert_select "div.project.label", :text => @project.name
+    assert_select "div.task.project > div.task_todo" do
+      assert_select "> div.label", :text => @project.name
+    end
   end
 
   test "#line_for_version" do
@@ -341,17 +352,19 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest
     version.stubs(:due_date).returns(today + 7)
     version.stubs(:visible_fixed_issues => stub(:completed_percent => 30))
     @output_buffer = @gantt.line_for_version(version, :format => :html)
-    assert_select "div.version.label", :text => /Foo/
-    assert_select "div.version.label", :text => /30%/
+    assert_select "div.task.version > div.task_todo" do
+      assert_select "> div.label", :text => 'Foo 30%'
+    end
   end
 
   test "#line_for_issue" do
     create_gantt
     issue = Issue.generate!(:project => @project, :start_date => today - 7, :due_date => today + 7, :done_ratio => 30)
     @output_buffer = @gantt.line_for_issue(issue, :format => :html)
-    assert_select "div.task.label", :text => /#{issue.status.name}/
-    assert_select "div.task.label", :text => /30%/
-    assert_select "div.tooltip", /#{issue.subject}/
+    assert_select "div.task_todo" do
+      assert_select "> div.label", :text => "#{issue.status.name} 30%"
+      assert_select "> div.tooltip", /#{issue.subject}/
+    end
   end
 
   test "#line todo line should start from the starting point on the left" do
@@ -365,8 +378,7 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest
     [gantt_start - 1, gantt_start].each do |start_date|
       @output_buffer = @gantt.line(start_date, gantt_start, 30, false, 'line', :format => :html, :zoom => 4)
       # the leftmost date (Date.today - 14 days)
-      assert_select 'div.task_todo[style*="left:0px"]', 1, @output_buffer
-      assert_select 'div.task_todo[style*="width:2px"]', 1, @output_buffer
+      assert_select 'div.task_todo[style*="left:0px"][style*="width:4px"]', 1, @output_buffer
     end
   end
 
@@ -375,74 +387,80 @@ class Redmine::Helpers::GanttHelperTest < Redmine::HelperTest
     [gantt_end, gantt_end + 1].each do |end_date|
       @output_buffer = @gantt.line(gantt_end, end_date, 30, false, 'line', :format => :html, :zoom => 4)
       # the rightmost date (Date.today + 14 days)
-      assert_select 'div.task_todo[style*="left:112px"]', 1, @output_buffer
-      assert_select 'div.task_todo[style*="width:2px"]', 1, @output_buffer
+      assert_select 'div.task_todo[style*="left:112px"][style*="width:4px"]', 1, @output_buffer
     end
   end
 
   test "#line todo line should be the total width" do
     create_gantt
     @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_todo[style*="width:58px"]', 1
+    assert_select 'div.task_todo[style*="width:60px"]', 1
   end
 
   test "#line late line should start from the starting point on the left" do
     create_gantt
     @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_late[style*="left:28px"]', 1
+    assert_select 'div.task_todo[style*="left:28px"]' do
+      assert_select '> div.task_late', 1
+    end
   end
 
   test "#line late line should be the total delayed width" do
     create_gantt
     @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_late[style*="width:30px"]', 1
+    assert_select 'div.task_late[style*="width:32px"]', 1
   end
 
   test "#line late line should be the same width as task_todo if start date and end date are the same day" do
     create_gantt
     @output_buffer = @gantt.line(today - 7, today - 7, 0, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_late[style*="width:2px"]', 1
-    assert_select 'div.task_todo[style*="width:2px"]', 1
+    assert_select 'div.task_todo[style*="width:4px"]' do
+      assert_select '> div.task_late[style*="width:4px"]', 1
+    end
   end
 
   test "#line late line should be the same width as task_todo if start date and today are the same day" do
     create_gantt
     @output_buffer = @gantt.line(today, today, 0, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_late[style*="width:2px"]', 1
-    assert_select 'div.task_todo[style*="width:2px"]', 1
+    assert_select 'div.task_todo[style*="width:4px"]' do
+      assert_select '> div.task_late[style*="width:4px"]', 1
+    end
   end
 
   test "#line done line should start from the starting point on the left" do
     create_gantt
     @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_done[style*="left:28px"]', 1
+    assert_select 'div.task_todo[style*="left:28px"]' do
+      assert_select '> div.task_done', 1
+    end
   end
 
   test "#line done line should be the width for the done ratio" do
     create_gantt
     @output_buffer = @gantt.line(today - 7, today + 7, 30, false, 'line', :format => :html, :zoom => 4)
-    # 15 days * 4 px * 30% - 2 px for borders = 16 px
-    assert_select 'div.task_done[style*="width:16px"]', 1
+    # 15 days * 4 px * 30% = 18 px
+    assert_select 'div.task_done[style*="width:18px"]', 1
   end
 
   test "#line done line should be the total width for 100% done ratio" do
     create_gantt
     @output_buffer = @gantt.line(today - 7, today + 7, 100, false, 'line', :format => :html, :zoom => 4)
-    # 15 days * 4 px - 2 px for borders = 58 px
-    assert_select 'div.task_done[style*="width:58px"]', 1
+    # 15 days * 4 px = 60 px
+    assert_select 'div.task_done[style*="width:60px"]', 1
   end
 
   test "#line done line should be the total width for 100% done ratio with same start and end dates" do
     create_gantt
     @output_buffer = @gantt.line(today + 7, today + 7, 100, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_done[style*="width:2px"]', 1
+    assert_select 'div.task_done[style*="width:4px"]', 1
   end
 
   test "#line done line should not be the total done width if the gantt starts after start date" do
     create_gantt
     @output_buffer = @gantt.line(today - 16, today - 2, 30, false, 'line', :format => :html, :zoom => 4)
-    assert_select 'div.task_done[style*="left:0px"]', 1
-    assert_select 'div.task_done[style*="width:8px"]', 1
+    assert_select 'div.task_todo[style*="left:0px"]' do
+      assert_select '> div.task_done[style*="width:10px"]', 1
+    end
   end
 
   test "#line starting marker should appear at the start date" do
