/* * GraphLine.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.workbench.views.vcs.dialog.graph; import com.google.gwt.canvas.client.Canvas; import com.google.gwt.canvas.dom.client.Context2d; import com.google.gwt.canvas.dom.client.Context2d.LineJoin; import com.google.gwt.safehtml.shared.SafeHtml; import org.rstudio.core.client.SafeHtmlUtil; public class GraphLine { public GraphLine(String value) { String[] vals = value.length() == 0 ? new String[] {} : value.split(" "); columns_ = new GraphColumn[vals.length]; for (int i = 0; i < columns_.length; i++) columns_[i] = new GraphColumn(vals[i]); } public GraphColumn[] getColumns() { return columns_; } public int getTotalWidth(GraphTheme theme) { int startColumns = 0; int endColumns = 0; for (GraphColumn c : columns_) { if (!c.start) startColumns++; if (!c.end) endColumns++; } return Math.max(startColumns, endColumns) * theme.getColumnWidth(); } public SafeHtml render(GraphTheme theme) { draw(s_canvas, theme); return SafeHtmlUtil.createOpenTag("img", "class", theme.getImgClassName(), "src", s_canvas.toDataUrl()); } private void draw(Canvas canvas, GraphTheme theme) { int height = theme.getRowHeight(); int colWidth = theme.getColumnWidth(); double pad = theme.getVerticalLinePadding(); canvas.setCoordinateSpaceHeight(height); canvas.setCoordinateSpaceWidth(colWidth * getTotalWidth(theme)); Context2d ctx = canvas.getContext2d(); //ctx.clearRect(0, 0, colWidth * columns_.length, height); ctx.translate(colWidth / 2.0, 0); int startPos = -1; int endPos = -1; int nexusColumn = -1; for (int i = 0; i < columns_.length; i++) { GraphColumn c = columns_[i]; if (!c.start) startPos++; if (!c.end) endPos++; ctx.setStrokeStyle(theme.getColorForId(c.id)); ctx.setLineWidth(theme.getStrokeWidth()); ctx.setLineJoin(LineJoin.ROUND); if (!c.nexus && !c.start && !c.end) { // Just draw a line from start to end position ctx.beginPath(); ctx.moveTo(startPos * colWidth, 0); ctx.lineTo(startPos * colWidth, pad); // This next lineTo helps ensure that the shape of the line looks // congruous to any specials on the same line ctx.lineTo(Math.min(startPos, endPos) * colWidth, height / 2.0); ctx.lineTo(endPos * colWidth, height - pad); ctx.lineTo(endPos * colWidth, height); ctx.stroke(); } else { // something special if (c.nexus) { nexusColumn = i; ctx.setFillStyle(theme.getColorForId(c.id)); } if (!c.start) { // draw from i to nexusColumn; ctx.beginPath(); ctx.moveTo(startPos * colWidth, 0); ctx.lineTo(startPos * colWidth, pad); ctx.lineTo(nexusColumn * colWidth, height / 2.0); ctx.stroke(); } if (!c.end) { // draw from nexusColumn to endPosition ctx.beginPath(); ctx.moveTo(nexusColumn * colWidth, height / 2.0); ctx.lineTo(endPos * colWidth, height - pad); ctx.lineTo(endPos * colWidth, height); ctx.stroke(); } } } // draw a circle on the nexus ctx.beginPath(); ctx.arc(nexusColumn * colWidth, height / 2.0, theme.getCircleRadius() + theme.getStrokeWidth(), 0, Math.PI * 2); ctx.closePath(); ctx.fill(); ctx.beginPath(); ctx.arc(nexusColumn * colWidth, height / 2.0, theme.getCircleRadius(), 0, Math.PI * 2); ctx.closePath(); ctx.setFillStyle("white"); ctx.fill(); } private GraphColumn[] columns_; // Use a static canvas to avoid the overhead of continually recreating them private static final Canvas s_canvas = Canvas.createIfSupported(); }