- updgraded commons-coded to the last version (needed for base64 encoding of data: uris)
- added the ability to embed the scatterplot inside the returned json data with data: uris (although it doesn't seem to work well) - connected the selection logic to the scatterfacets (although it doesn't seem to filter the rows... and I'm puzzled as why) - reduced cut/paste and code overlap between the scatterplot generator and the scatterplot facet git-svn-id: http://google-refine.googlecode.com/svn/trunk@490 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
8085208cf0
commit
7a716a4a1b
@ -8,7 +8,7 @@
|
||||
<classpathentry kind="lib" path="lib/jetty-6.1.22.jar" sourcepath="lib-src/jetty-6.1.22-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jetty-util-6.1.22.jar" sourcepath="lib-src/jetty-util-6.1.22-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/log4j-1.2.15.jar" sourcepath="lib-src/log4j-1.2.15-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-codec-1.3.jar" sourcepath="lib-src/commons-codec-1.3-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-codec-1.4.jar" sourcepath="lib-src/commons-codec-1.4-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-lang-2.5.jar" sourcepath="lib-src/commons-lang-2.5-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/commons-fileupload-1.2.1.jar" sourcepath="lib-src/commons-fileupload-1.2.1-sources.jar"/>
|
||||
<classpathentry kind="lib" path="lib/json-20100208.jar" sourcepath="lib-src/json-20100208-sources.jar"/>
|
||||
|
3
.settings/org.eclipse.core.resources.prefs
Normal file
3
.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,3 @@
|
||||
#Fri Apr 16 12:46:04 PDT 2010
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/webapp/scripts/dialogs/scatterplot-dialog.js=UTF-8
|
Binary file not shown.
BIN
lib-src/commons-codec-1.4-sources.jar
Normal file
BIN
lib-src/commons-codec-1.4-sources.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
lib/commons-codec-1.4.jar
Normal file
BIN
lib/commons-codec-1.4.jar
Normal file
Binary file not shown.
@ -39,9 +39,11 @@ public class Engine implements Jsonizable {
|
||||
public FilteredRows getFilteredRows(Facet except, boolean includeContextual) {
|
||||
ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows(includeContextual, _includeDependent);
|
||||
for (Facet facet : _facets) {
|
||||
System.out.println("facet: " + facet);
|
||||
if (facet != except) {
|
||||
RowFilter rowFilter = facet.getRowFilter();
|
||||
if (rowFilter != null) {
|
||||
System.out.println(" rowFilter: " + rowFilter);
|
||||
cfr.add(rowFilter);
|
||||
}
|
||||
}
|
||||
|
@ -1,202 +0,0 @@
|
||||
package com.metaweb.gridworks.browsing.charting;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.metaweb.gridworks.browsing.Engine;
|
||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||
import com.metaweb.gridworks.browsing.facets.NumericBinIndex;
|
||||
import com.metaweb.gridworks.expr.Evaluable;
|
||||
import com.metaweb.gridworks.expr.MetaParser;
|
||||
import com.metaweb.gridworks.expr.ParsingException;
|
||||
import com.metaweb.gridworks.model.Cell;
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.Row;
|
||||
|
||||
public class ScatterplotCharter {
|
||||
|
||||
private static final int LIN = 0;
|
||||
private static final int LOG = 1;
|
||||
private static final int POLAR = 2;
|
||||
|
||||
private static int getAxisDim(String type) {
|
||||
if ("log".equals(type)) {
|
||||
return LOG;
|
||||
} else if ("pol".equals(type) || "polar".equals(type)) {
|
||||
return POLAR;
|
||||
} else {
|
||||
return LIN;
|
||||
}
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return "image/png";
|
||||
}
|
||||
|
||||
public void draw(OutputStream output, Project project, Engine engine, JSONObject options) throws IOException, JSONException {
|
||||
|
||||
DrawingRowVisitor drawingVisitor = new DrawingRowVisitor(project, options);
|
||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
||||
filteredRows.accept(project, drawingVisitor);
|
||||
|
||||
ImageIO.write(drawingVisitor.getImage(), "png", output);
|
||||
}
|
||||
|
||||
class DrawingRowVisitor implements RowVisitor {
|
||||
|
||||
boolean process = true;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
int col_x;
|
||||
int col_y;
|
||||
int dim;
|
||||
|
||||
double w;
|
||||
double h;
|
||||
double min_x;
|
||||
double min_y;
|
||||
double max_x;
|
||||
double max_y;
|
||||
double delta_x;
|
||||
double delta_y;
|
||||
double log_delta_x;
|
||||
double log_delta_y;
|
||||
double rx;
|
||||
double ry;
|
||||
double dot;
|
||||
|
||||
Color color;
|
||||
|
||||
NumericBinIndex index_x;
|
||||
NumericBinIndex index_y;
|
||||
|
||||
BufferedImage image;
|
||||
Graphics2D g2;
|
||||
|
||||
public DrawingRowVisitor(Project project, JSONObject o) throws JSONException {
|
||||
String col_x_name = o.getString("cx");
|
||||
Column column_x = project.columnModel.getColumnByName(col_x_name);
|
||||
if (column_x != null) {
|
||||
col_x = column_x.getCellIndex();
|
||||
index_x = getBinIndex(project, column_x);
|
||||
min_x = index_x.getMin();
|
||||
max_x = index_x.getMax();
|
||||
}
|
||||
|
||||
String col_y_name = o.getString("cy");
|
||||
Column column_y = project.columnModel.getColumnByName(col_y_name);
|
||||
if (column_y != null) {
|
||||
col_y = column_y.getCellIndex();
|
||||
index_y = getBinIndex(project, column_y);
|
||||
min_y = index_y.getMin();
|
||||
max_y = index_y.getMax();
|
||||
}
|
||||
|
||||
width = (o.has("w")) ? o.getInt("w") : 50;
|
||||
height = (o.has("h")) ? o.getInt("h") : 50;
|
||||
|
||||
dot = (o.has("dot")) ? o.getDouble("dot") : 0.2d;
|
||||
|
||||
dim = (o.has("dim")) ? getAxisDim(o.getString("dim")) : LIN;
|
||||
|
||||
delta_x = max_x - min_x;
|
||||
delta_y = max_y - min_y;
|
||||
|
||||
if (dim == POLAR) {
|
||||
rx = (o.has("rx")) ? o.getDouble("rx") : 0.0d;
|
||||
ry = (o.has("ry")) ? o.getDouble("ry") : 0.0d;
|
||||
} else if (dim == LOG) {
|
||||
log_delta_x = Math.log10(delta_x);
|
||||
log_delta_y = Math.log10(delta_y);
|
||||
}
|
||||
|
||||
String color_str = (o.has("color")) ? o.getString("color") : "000000";
|
||||
color = new Color(Integer.parseInt(color_str,16));
|
||||
|
||||
w = (double) width;
|
||||
h = (double) height;
|
||||
|
||||
if (index_x.isNumeric() && index_y.isNumeric()) {
|
||||
image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
g2 = (Graphics2D) image.getGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setStroke(new BasicStroke(1.0f));
|
||||
AffineTransform t = AffineTransform.getTranslateInstance(0,h);
|
||||
t.concatenate(AffineTransform.getScaleInstance(1.0d, -1.0d));
|
||||
g2.setTransform(t);
|
||||
g2.setColor(color);
|
||||
g2.setPaint(color);
|
||||
} else {
|
||||
image = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
process = false;
|
||||
}
|
||||
}
|
||||
|
||||
private NumericBinIndex getBinIndex(Project project, Column column) {
|
||||
String expression = "value";
|
||||
String key = "numeric-bin:" + expression;
|
||||
Evaluable eval = null;
|
||||
try {
|
||||
eval = MetaParser.parse(expression);
|
||||
} catch (ParsingException e) {
|
||||
// this should never happen
|
||||
}
|
||||
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
||||
if (index == null) {
|
||||
index = new NumericBinIndex(project, column.getName(), column.getCellIndex(), eval);
|
||||
column.setPrecompute(key, index);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
||||
if (process) {
|
||||
Cell cellx = row.getCell(col_x);
|
||||
Cell celly = row.getCell(col_y);
|
||||
if ((cellx != null && cellx.value != null && cellx.value instanceof Number) &&
|
||||
(celly != null && celly.value != null && celly.value instanceof Number))
|
||||
{
|
||||
double xv = ((Number) cellx.value).doubleValue();
|
||||
double yv = ((Number) celly.value).doubleValue();
|
||||
|
||||
double x;
|
||||
double y;
|
||||
|
||||
if (dim == LOG) {
|
||||
x = Math.log10(xv - min_x) * w / log_delta_x - dot / 2;
|
||||
y = Math.log10(yv - min_y) * h / log_delta_y - dot / 2;
|
||||
} else if (dim == POLAR) {
|
||||
x = (xv - min_x) * w / delta_x - dot / 2;
|
||||
y = (yv - min_y) * h / delta_y - dot / 2;
|
||||
} else {
|
||||
x = (xv - min_x) * w / delta_x - dot / 2;
|
||||
y = (yv - min_y) * h / delta_y - dot / 2;
|
||||
}
|
||||
g2.fill(new Rectangle2D.Double(x, y, dot, dot));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public RenderedImage getImage() {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.metaweb.gridworks.browsing.facets;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
|
||||
import com.metaweb.gridworks.browsing.RowVisitor;
|
||||
import com.metaweb.gridworks.model.Cell;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.Row;
|
||||
|
||||
public class ScatterplotDrawingRowVisitor implements RowVisitor {
|
||||
|
||||
int col_x;
|
||||
int col_y;
|
||||
int size;
|
||||
int dim_x;
|
||||
int dim_y;
|
||||
int rotation;
|
||||
|
||||
double l;
|
||||
double dot;
|
||||
|
||||
double from_x;
|
||||
double from_y;
|
||||
double to_x;
|
||||
double to_y;
|
||||
|
||||
double min_x;
|
||||
double max_x;
|
||||
double min_y;
|
||||
double max_y;
|
||||
|
||||
Color color;
|
||||
|
||||
BufferedImage image;
|
||||
Graphics2D g2;
|
||||
|
||||
public ScatterplotDrawingRowVisitor(
|
||||
int col_x, int col_y, double min_x, double max_x, double min_y, double max_y,
|
||||
int size, int dim_x, int dim_y, int rotation, double dot, Color color,
|
||||
double from_x, double from_y, double to_x, double to_y)
|
||||
{
|
||||
this.col_x = col_x;
|
||||
this.col_y = col_y;
|
||||
this.min_x = min_x;
|
||||
this.min_y = min_y;
|
||||
this.max_x = max_x;
|
||||
this.max_y = max_y;
|
||||
this.size = size;
|
||||
this.dot = dot;
|
||||
this.color = color;
|
||||
this.dim_x = dim_x;
|
||||
this.dim_y = dim_y;
|
||||
this.rotation = rotation;
|
||||
this.from_x = from_x;
|
||||
this.from_y = from_y;
|
||||
this.to_x = to_x;
|
||||
this.to_y = to_y;
|
||||
|
||||
l = (double) size;
|
||||
|
||||
image = new BufferedImage(size, size, BufferedImage.TYPE_4BYTE_ABGR);
|
||||
g2 = (Graphics2D) image.getGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2.setStroke(new BasicStroke(1.0f));
|
||||
AffineTransform t = AffineTransform.getTranslateInstance(0,l);
|
||||
t.concatenate(AffineTransform.getScaleInstance(1.0d, -1.0d));
|
||||
g2.setTransform(t);
|
||||
g2.setColor(color);
|
||||
g2.setPaint(color);
|
||||
}
|
||||
|
||||
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
|
||||
Cell cellx = row.getCell(col_x);
|
||||
Cell celly = row.getCell(col_y);
|
||||
if ((cellx != null && cellx.value != null && cellx.value instanceof Number) &&
|
||||
(celly != null && celly.value != null && celly.value instanceof Number))
|
||||
{
|
||||
double xv = ((Number) cellx.value).doubleValue();
|
||||
double yv = ((Number) celly.value).doubleValue();
|
||||
|
||||
Point2D.Double p = new Point2D.Double(xv,yv);
|
||||
|
||||
p = ScatterplotFacet.translateCoordinates(p, dim_x, dim_y, rotation, l, min_x, max_x, min_y, max_y);
|
||||
|
||||
g2.fill(new Rectangle2D.Double(p.x - dot / 2, p.y - dot / 2, dot, dot));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public RenderedImage getImage() {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,21 @@
|
||||
package com.metaweb.gridworks.browsing.facets;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONWriter;
|
||||
|
||||
import com.metaweb.gridworks.Gridworks;
|
||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||
import com.metaweb.gridworks.browsing.filters.DualExpressionsNumberComparisonRowFilter;
|
||||
import com.metaweb.gridworks.browsing.filters.RowFilter;
|
||||
@ -17,144 +27,221 @@ import com.metaweb.gridworks.model.Project;
|
||||
|
||||
public class ScatterplotFacet implements Facet {
|
||||
|
||||
public static final int LIN = 0;
|
||||
public static final int LOG = 1;
|
||||
|
||||
public static final int NO_ROTATION = 0;
|
||||
public static final int ROTATE_CW = 1;
|
||||
public static final int ROTATE_CCW = 2;
|
||||
|
||||
/*
|
||||
* Configuration, from the client side
|
||||
*/
|
||||
protected String _name; // name of facet
|
||||
protected String name; // name of facet
|
||||
|
||||
protected String _x_expression; // expression to compute the x numeric value(s) per row
|
||||
protected String _y_expression; // expression to compute the y numeric value(s) per row
|
||||
protected String _x_columnName; // column to base the x expression on, if any
|
||||
protected String _y_columnName; // column to base the y expression on, if any
|
||||
protected String expression_x; // expression to compute the x numeric value(s) per row
|
||||
protected String expression_y; // expression to compute the y numeric value(s) per row
|
||||
protected String columnName_x; // column to base the x expression on, if any
|
||||
protected String columnName_y; // column to base the y expression on, if any
|
||||
|
||||
protected double _x_from; // the numeric selection for the x axis
|
||||
protected double _x_to;
|
||||
protected double _y_from; // the numeric selection for the y axis
|
||||
protected double _y_to;
|
||||
protected double from_x; // the numeric selection for the x axis
|
||||
protected double to_x;
|
||||
protected double from_y; // the numeric selection for the y axis
|
||||
protected double to_y;
|
||||
|
||||
protected double _x_min;
|
||||
protected double _x_max;
|
||||
protected double _y_min;
|
||||
protected double _y_max;
|
||||
protected double min_x;
|
||||
protected double max_x;
|
||||
protected double min_y;
|
||||
protected double max_y;
|
||||
|
||||
protected int size;
|
||||
protected int dim_x;
|
||||
protected int dim_y;
|
||||
protected int rotation;
|
||||
|
||||
protected double l;
|
||||
protected double dot;
|
||||
|
||||
protected String image;
|
||||
|
||||
protected String color_str;
|
||||
protected Color color;
|
||||
|
||||
/*
|
||||
* Derived configuration data
|
||||
*/
|
||||
protected int _x_cellIndex;
|
||||
protected int _y_cellIndex;
|
||||
protected Evaluable _x_eval;
|
||||
protected Evaluable _y_eval;
|
||||
protected String _x_errorMessage;
|
||||
protected String _y_errorMessage;
|
||||
protected int columnIndex_x;
|
||||
protected int columnIndex_y;
|
||||
protected Evaluable eval_x;
|
||||
protected Evaluable eval_y;
|
||||
protected String errorMessage_x;
|
||||
protected String errorMessage_y;
|
||||
|
||||
protected boolean _selected; // false if we're certain that all rows will match
|
||||
// and there isn't any filtering to do
|
||||
protected boolean selected; // false if we're certain that all rows will match
|
||||
// and there isn't any filtering to do
|
||||
|
||||
public ScatterplotFacet() {
|
||||
}
|
||||
public static final String NAME = "name";
|
||||
public static final String IMAGE = "image";
|
||||
public static final String COLOR = "color";
|
||||
public static final String SIZE = "l";
|
||||
public static final String ROTATION = "r";
|
||||
public static final String DOT = "dot";
|
||||
public static final String DIM_X = "dim_x";
|
||||
public static final String DIM_Y = "dim_y";
|
||||
|
||||
private static final String X_MIN = "x_min";
|
||||
private static final String X_MAX = "x_max";
|
||||
private static final String X_TO = "x_to";
|
||||
private static final String X_FROM = "x_from";
|
||||
private static final String Y_MIN = "y_min";
|
||||
private static final String Y_MAX = "y_max";
|
||||
private static final String Y_TO = "y_to";
|
||||
private static final String Y_FROM = "y_from";
|
||||
public static final String X_COLUMN_NAME = "cx";
|
||||
public static final String X_EXPRESSION = "ex";
|
||||
public static final String MIN_X = "min_x";
|
||||
public static final String MAX_X = "max_x";
|
||||
public static final String TO_X = "to_x";
|
||||
public static final String FROM_X = "from_x";
|
||||
public static final String ERROR_X = "error_x";
|
||||
|
||||
public void write(JSONWriter writer, Properties options)
|
||||
throws JSONException {
|
||||
public static final String Y_COLUMN_NAME = "cy";
|
||||
public static final String Y_EXPRESSION = "ey";
|
||||
public static final String MIN_Y = "min_y";
|
||||
public static final String MAX_Y = "max_y";
|
||||
public static final String TO_Y = "to_y";
|
||||
public static final String FROM_Y = "from_y";
|
||||
public static final String ERROR_Y = "error_y";
|
||||
|
||||
private static final boolean IMAGE_URI = false;
|
||||
|
||||
public static String EMPTY_IMAGE;
|
||||
|
||||
static {
|
||||
try {
|
||||
EMPTY_IMAGE = serializeImage(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR));
|
||||
} catch (IOException e) {
|
||||
EMPTY_IMAGE = "";
|
||||
}
|
||||
}
|
||||
|
||||
public void write(JSONWriter writer, Properties options) throws JSONException {
|
||||
|
||||
writer.object();
|
||||
writer.key("name"); writer.value(_name);
|
||||
writer.key("x_expression"); writer.value(_x_expression);
|
||||
writer.key("x_columnName"); writer.value(_x_columnName);
|
||||
writer.key("y_expression"); writer.value(_y_expression);
|
||||
writer.key("y_columnName"); writer.value(_y_columnName);
|
||||
|
||||
if (_x_errorMessage != null) {
|
||||
writer.key("x_error"); writer.value(_x_errorMessage);
|
||||
writer.key(NAME); writer.value(name);
|
||||
writer.key(X_COLUMN_NAME); writer.value(columnName_x);
|
||||
writer.key(X_EXPRESSION); writer.value(expression_x);
|
||||
writer.key(Y_COLUMN_NAME); writer.value(columnName_y);
|
||||
writer.key(Y_EXPRESSION); writer.value(expression_y);
|
||||
writer.key(SIZE); writer.value(size);
|
||||
writer.key(DOT); writer.value(dot);
|
||||
writer.key(ROTATION); writer.value(rotation);
|
||||
writer.key(DIM_X); writer.value(dim_x);
|
||||
writer.key(DIM_Y); writer.value(dim_y);
|
||||
writer.key(COLOR); writer.value(color_str);
|
||||
|
||||
if (IMAGE_URI) {
|
||||
writer.key(IMAGE); writer.value(image);
|
||||
}
|
||||
|
||||
if (errorMessage_x != null) {
|
||||
writer.key(ERROR_X); writer.value(errorMessage_x);
|
||||
} else {
|
||||
if (!Double.isInfinite(_x_min) && !Double.isInfinite(_x_max)) {
|
||||
writer.key(X_MIN); writer.value(_x_min);
|
||||
writer.key(X_MAX); writer.value(_x_max);
|
||||
writer.key(X_FROM); writer.value(_x_from);
|
||||
writer.key(X_TO); writer.value(_x_to);
|
||||
}
|
||||
if (!Double.isInfinite(_y_min) && !Double.isInfinite(_y_max)) {
|
||||
writer.key(Y_MIN); writer.value(_y_min);
|
||||
writer.key(Y_MAX); writer.value(_y_max);
|
||||
writer.key(Y_FROM); writer.value(_y_from);
|
||||
writer.key(Y_TO); writer.value(_y_to);
|
||||
if (!Double.isInfinite(min_x) && !Double.isInfinite(max_x)) {
|
||||
writer.key(MIN_X); writer.value(min_x);
|
||||
writer.key(MAX_X); writer.value(max_x);
|
||||
writer.key(FROM_X); writer.value(from_x);
|
||||
writer.key(TO_X); writer.value(to_x);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorMessage_y != null) {
|
||||
writer.key(ERROR_Y); writer.value(errorMessage_y);
|
||||
} else {
|
||||
if (!Double.isInfinite(min_y) && !Double.isInfinite(max_y)) {
|
||||
writer.key(MIN_Y); writer.value(min_y);
|
||||
writer.key(MAX_Y); writer.value(max_y);
|
||||
writer.key(FROM_Y); writer.value(from_y);
|
||||
writer.key(TO_Y); writer.value(to_y);
|
||||
}
|
||||
}
|
||||
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
public void initializeFromJSON(Project project, JSONObject o) throws Exception {
|
||||
_name = o.getString("name");
|
||||
name = o.getString(NAME);
|
||||
|
||||
_x_expression = o.getString("x_expression");
|
||||
_x_columnName = o.getString("x_columnName");
|
||||
size = (o.has(SIZE)) ? o.getInt(SIZE) : 100;
|
||||
|
||||
dot = (o.has(DOT)) ? o.getInt(DOT) : 0.5d;
|
||||
|
||||
if (_x_columnName.length() > 0) {
|
||||
Column x_column = project.columnModel.getColumnByName(_x_columnName);
|
||||
dim_x = (o.has(DIM_X)) ? getAxisDim(o.getString(DIM_X)) : LIN;
|
||||
dim_y = (o.has(DIM_Y)) ? getAxisDim(o.getString(DIM_Y)) : LIN;
|
||||
|
||||
rotation = (o.has(ROTATION)) ? getRotation(o.getString(ROTATION)) : NO_ROTATION;
|
||||
|
||||
color_str = (o.has(COLOR)) ? o.getString(COLOR) : "000000";
|
||||
color = new Color(Integer.parseInt(color_str,16));
|
||||
|
||||
columnName_x = o.getString(X_COLUMN_NAME);
|
||||
expression_x = o.getString(X_EXPRESSION);
|
||||
|
||||
if (columnName_x.length() > 0) {
|
||||
Column x_column = project.columnModel.getColumnByName(columnName_x);
|
||||
if (x_column != null) {
|
||||
_x_cellIndex = x_column.getCellIndex();
|
||||
columnIndex_x = x_column.getCellIndex();
|
||||
} else {
|
||||
_x_errorMessage = "No column named " + _x_columnName;
|
||||
errorMessage_x = "No column named " + columnName_x;
|
||||
}
|
||||
} else {
|
||||
_x_cellIndex = -1;
|
||||
columnIndex_x = -1;
|
||||
}
|
||||
|
||||
try {
|
||||
_x_eval = MetaParser.parse(_x_expression);
|
||||
eval_x = MetaParser.parse(expression_x);
|
||||
} catch (ParsingException e) {
|
||||
_x_errorMessage = e.getMessage();
|
||||
errorMessage_x = e.getMessage();
|
||||
}
|
||||
|
||||
if (o.has(X_FROM) && o.has(X_TO)) {
|
||||
_x_from = o.getDouble(X_FROM);
|
||||
_x_to = o.getDouble(X_TO);
|
||||
_selected = true;
|
||||
if (o.has(FROM_X) && o.has(TO_X)) {
|
||||
from_x = o.getDouble(FROM_X);
|
||||
to_x = o.getDouble(TO_X);
|
||||
selected = true;
|
||||
}
|
||||
|
||||
_y_expression = o.getString("y_expression");
|
||||
_y_columnName = o.getString("y_columnName");
|
||||
columnName_y = o.getString(Y_COLUMN_NAME);
|
||||
expression_y = o.getString(Y_EXPRESSION);
|
||||
|
||||
if (_y_columnName.length() > 0) {
|
||||
Column y_column = project.columnModel.getColumnByName(_y_columnName);
|
||||
if (columnName_y.length() > 0) {
|
||||
Column y_column = project.columnModel.getColumnByName(columnName_y);
|
||||
if (y_column != null) {
|
||||
_y_cellIndex = y_column.getCellIndex();
|
||||
columnIndex_y = y_column.getCellIndex();
|
||||
} else {
|
||||
_y_errorMessage = "No column named " + _y_columnName;
|
||||
errorMessage_y = "No column named " + columnName_y;
|
||||
}
|
||||
} else {
|
||||
_y_cellIndex = -1;
|
||||
columnIndex_y = -1;
|
||||
}
|
||||
|
||||
try {
|
||||
_y_eval = MetaParser.parse(_y_expression);
|
||||
eval_y = MetaParser.parse(expression_y);
|
||||
} catch (ParsingException e) {
|
||||
_y_errorMessage = e.getMessage();
|
||||
errorMessage_y = e.getMessage();
|
||||
}
|
||||
|
||||
if (o.has(Y_FROM) && o.has(Y_TO)) {
|
||||
_y_from = o.getDouble(Y_FROM);
|
||||
_y_to = o.getDouble(Y_TO);
|
||||
_selected = true;
|
||||
if (o.has(FROM_Y) && o.has(TO_Y)) {
|
||||
from_y = o.getDouble(FROM_Y);
|
||||
to_y = o.getDouble(TO_Y);
|
||||
selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
public RowFilter getRowFilter() {
|
||||
if (_selected &&
|
||||
_x_eval != null && _x_errorMessage == null &&
|
||||
_y_eval != null && _y_errorMessage == null)
|
||||
if (selected &&
|
||||
eval_x != null && errorMessage_x == null &&
|
||||
eval_y != null && errorMessage_y == null)
|
||||
{
|
||||
return new DualExpressionsNumberComparisonRowFilter(_x_eval, _x_columnName, _x_cellIndex, _y_eval, _y_columnName, _y_cellIndex) {
|
||||
return new DualExpressionsNumberComparisonRowFilter(eval_x, columnName_x, columnIndex_x, eval_y, columnName_y, columnIndex_y) {
|
||||
protected boolean checkValues(double x, double y) {
|
||||
return x >= _x_from && x < _x_to && y >= _y_from && y < _y_to;
|
||||
Point2D.Double p = new Point2D.Double(x,y);
|
||||
p = translateCoordinates(p, dim_x, dim_y, rotation, l, min_x, max_x, min_y, max_y);
|
||||
boolean value = p.x >= from_x && p.x < to_x && p.y >= from_y && p.y < to_y;
|
||||
System.out.println(p + " " + value);
|
||||
return value;
|
||||
};
|
||||
};
|
||||
} else {
|
||||
@ -163,44 +250,129 @@ public class ScatterplotFacet implements Facet {
|
||||
}
|
||||
|
||||
public void computeChoices(Project project, FilteredRows filteredRows) {
|
||||
if (_x_eval != null && _y_eval != null && _x_errorMessage == null && _y_errorMessage == null) {
|
||||
Column column_x = project.columnModel.getColumnByCellIndex(_x_cellIndex);
|
||||
String key_x = "numeric-bin:" + _x_expression;
|
||||
NumericBinIndex index_x = (NumericBinIndex) column_x.getPrecompute(key_x);
|
||||
if (index_x == null) {
|
||||
index_x = new NumericBinIndex(project, _x_columnName, _x_cellIndex, _x_eval);
|
||||
column_x.setPrecompute(key_x, index_x);
|
||||
}
|
||||
if (eval_x != null && eval_y != null && errorMessage_x == null && errorMessage_y == null) {
|
||||
Column column_x = project.columnModel.getColumnByCellIndex(columnIndex_x);
|
||||
NumericBinIndex index_x = getBinIndex(project, column_x, eval_x, expression_x);
|
||||
|
||||
_x_min = index_x.getMin();
|
||||
_x_max = index_x.getMax();
|
||||
min_x = index_x.getMin();
|
||||
max_x = index_x.getMax();
|
||||
|
||||
if (_selected) {
|
||||
_x_from = Math.max(_x_from, _x_min);
|
||||
_x_to = Math.min(_x_to, _x_max);
|
||||
if (selected) {
|
||||
from_x = Math.max(from_x, min_x);
|
||||
to_x = Math.min(to_x, max_x);
|
||||
} else {
|
||||
_x_from = _x_min;
|
||||
_x_to = _x_max;
|
||||
from_x = min_x;
|
||||
to_x = max_x;
|
||||
}
|
||||
|
||||
Column column_y = project.columnModel.getColumnByCellIndex(columnIndex_y);
|
||||
NumericBinIndex index_y = getBinIndex(project, column_y, eval_y, expression_y);
|
||||
|
||||
min_y = index_y.getMin();
|
||||
max_y = index_y.getMax();
|
||||
|
||||
Column column_y = project.columnModel.getColumnByCellIndex(_y_cellIndex);
|
||||
String key_y = "numeric-bin:" + _y_expression;
|
||||
NumericBinIndex index_y = (NumericBinIndex) column_y.getPrecompute(key_y);
|
||||
if (index_y == null) {
|
||||
index_y = new NumericBinIndex(project, _y_columnName, _y_cellIndex, _y_eval);
|
||||
column_y.setPrecompute(key_y, index_y);
|
||||
}
|
||||
|
||||
_y_min = index_y.getMin();
|
||||
_y_max = index_y.getMax();
|
||||
|
||||
if (_selected) {
|
||||
_y_from = Math.max(_y_from, _y_min);
|
||||
_y_to = Math.min(_y_to, _y_max);
|
||||
if (selected) {
|
||||
from_y = Math.max(from_y, min_y);
|
||||
to_y = Math.min(to_y, max_y);
|
||||
} else {
|
||||
_y_from = _y_min;
|
||||
_y_to = _y_max;
|
||||
from_y = min_y;
|
||||
to_y = max_y;
|
||||
}
|
||||
|
||||
if (IMAGE_URI) {
|
||||
if (index_x.isNumeric() && index_y.isNumeric()) {
|
||||
ScatterplotDrawingRowVisitor drawer = new ScatterplotDrawingRowVisitor(
|
||||
columnIndex_x, columnIndex_y, min_x, max_x, min_y, max_y,
|
||||
size, dim_x, dim_y, rotation, dot, color,
|
||||
from_x, from_y, to_x, to_y
|
||||
);
|
||||
filteredRows.accept(project, drawer);
|
||||
|
||||
try {
|
||||
image = serializeImage(drawer.getImage());
|
||||
} catch (IOException e) {
|
||||
Gridworks.warn("Exception caught while generating the image", e);
|
||||
}
|
||||
} else {
|
||||
image = EMPTY_IMAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String serializeImage(RenderedImage image) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
|
||||
ImageIO.write(image, "png", output);
|
||||
output.close();
|
||||
String encoded = Base64.encodeBase64String(output.toByteArray());
|
||||
String url = "data:image/png;base64," + encoded;
|
||||
return url;
|
||||
}
|
||||
|
||||
public static int getAxisDim(String type) {
|
||||
return ("log".equals(type.toLowerCase())) ? LOG : LIN;
|
||||
}
|
||||
|
||||
public static int getRotation(String rotation) {
|
||||
rotation = rotation.toLowerCase();
|
||||
if ("cw".equals(rotation) || "right".equals(rotation)) {
|
||||
return ScatterplotFacet.ROTATE_CW;
|
||||
} else if ("ccw".equals(rotation) || "left".equals(rotation)) {
|
||||
return ScatterplotFacet.ROTATE_CCW;
|
||||
} else {
|
||||
return NO_ROTATION;
|
||||
}
|
||||
}
|
||||
|
||||
public static NumericBinIndex getBinIndex(Project project, Column column, Evaluable eval, String expression) {
|
||||
String key = "numeric-bin:" + expression;
|
||||
if (eval == null) {
|
||||
try {
|
||||
eval = MetaParser.parse(expression);
|
||||
} catch (ParsingException e) {
|
||||
Gridworks.warn("Error parsing expression",e);
|
||||
}
|
||||
}
|
||||
NumericBinIndex index = (NumericBinIndex) column.getPrecompute(key);
|
||||
if (index == null) {
|
||||
index = new NumericBinIndex(project, column.getName(), column.getCellIndex(), eval);
|
||||
column.setPrecompute(key, index);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public static Point2D.Double translateCoordinates(Point2D.Double p, int dim_x, int dim_y, int rotation, double l, double min_x, double max_x, double min_y, double max_y) {
|
||||
double x = p.x;
|
||||
double y = p.y;
|
||||
|
||||
if (dim_x == ScatterplotFacet.LOG) {
|
||||
x = Math.log10(p.x - min_x) * l / Math.log10(max_x - min_x);
|
||||
} else {
|
||||
x = (p.x - min_x) * l / (max_x - min_x);
|
||||
}
|
||||
|
||||
if (dim_y == ScatterplotFacet.LOG) {
|
||||
y = Math.log10(p.y - min_y) * l / Math.log10(max_y - min_y);
|
||||
} else {
|
||||
y = (p.y - min_y) * l / (max_y - min_y);
|
||||
}
|
||||
|
||||
if (rotation == ScatterplotFacet.ROTATE_CW) {
|
||||
double x1 = (x + y) / 2;
|
||||
double y1 = (l - x + y) / 2;
|
||||
x = x1;
|
||||
y = y1;
|
||||
} else if (rotation == ScatterplotFacet.ROTATE_CCW) {
|
||||
double x1 = (l - y + x) / 2;
|
||||
double y1 = (y + x) / 2;
|
||||
x = x1;
|
||||
y = y1;
|
||||
}
|
||||
|
||||
p.x = x;
|
||||
p.y = y;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ abstract public class DualExpressionsNumberComparisonRowFilter implements RowFil
|
||||
final protected String _y_columnName;
|
||||
final protected int _y_cellIndex;
|
||||
|
||||
public DualExpressionsNumberComparisonRowFilter(
|
||||
public DualExpressionsNumberComparisonRowFilter (
|
||||
Evaluable x_evaluable,
|
||||
String x_columnName,
|
||||
int x_cellIndex,
|
||||
|
@ -1,48 +1,173 @@
|
||||
package com.metaweb.gridworks.commands.info;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.metaweb.gridworks.Gridworks;
|
||||
import com.metaweb.gridworks.browsing.Engine;
|
||||
import com.metaweb.gridworks.browsing.charting.ScatterplotCharter;
|
||||
import com.metaweb.gridworks.browsing.FilteredRows;
|
||||
import com.metaweb.gridworks.browsing.facets.NumericBinIndex;
|
||||
import com.metaweb.gridworks.browsing.facets.ScatterplotDrawingRowVisitor;
|
||||
import com.metaweb.gridworks.browsing.facets.ScatterplotFacet;
|
||||
import com.metaweb.gridworks.commands.Command;
|
||||
import com.metaweb.gridworks.expr.Evaluable;
|
||||
import com.metaweb.gridworks.expr.MetaParser;
|
||||
import com.metaweb.gridworks.expr.ParsingException;
|
||||
import com.metaweb.gridworks.model.Column;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
|
||||
public class GetScatterplotCommand extends Command {
|
||||
|
||||
final private ScatterplotCharter charter = new ScatterplotCharter();
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
//long start = System.currentTimeMillis();
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Project project = getProject(request);
|
||||
Engine engine = getEngine(request, project);
|
||||
JSONObject conf = getJsonParameter(request,"plotter");
|
||||
|
||||
response.setHeader("Content-Type", charter.getContentType());
|
||||
response.setHeader("Content-Type", "image/png");
|
||||
|
||||
ServletOutputStream sos = null;
|
||||
|
||||
try {
|
||||
sos = response.getOutputStream();
|
||||
charter.draw(sos, project, engine, conf);
|
||||
draw(sos, project, engine, conf);
|
||||
} finally {
|
||||
sos.close();
|
||||
}
|
||||
|
||||
//Gridworks.log("Drawn scatterplot in " + (System.currentTimeMillis() - start) + "ms");
|
||||
Gridworks.log("Drawn scatterplot in " + (System.currentTimeMillis() - start) + "ms");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
respondException(response, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(OutputStream output, Project project, Engine engine, JSONObject o) throws IOException, JSONException {
|
||||
|
||||
double min_x = 0;
|
||||
double min_y = 0;
|
||||
double max_x = 0;
|
||||
double max_y = 0;
|
||||
|
||||
double from_x = 0;
|
||||
double to_x = 0;
|
||||
double from_y = 0;
|
||||
double to_y = 0;
|
||||
|
||||
int columnIndex_x = 0;
|
||||
int columnIndex_y = 0;
|
||||
|
||||
Evaluable eval_x = null;
|
||||
Evaluable eval_y = null;
|
||||
|
||||
int size = (o.has(ScatterplotFacet.SIZE)) ? o.getInt(ScatterplotFacet.SIZE) : 100;
|
||||
|
||||
double dot = (o.has(ScatterplotFacet.DOT)) ? o.getDouble(ScatterplotFacet.DOT) : 100;
|
||||
|
||||
int dim_x = (o.has(ScatterplotFacet.DIM_X)) ? ScatterplotFacet.getAxisDim(o.getString(ScatterplotFacet.DIM_X)) : ScatterplotFacet.LIN;
|
||||
int dim_y = (o.has(ScatterplotFacet.DIM_Y)) ? ScatterplotFacet.getAxisDim(o.getString(ScatterplotFacet.DIM_Y)) : ScatterplotFacet.LIN;
|
||||
|
||||
int rotation = (o.has(ScatterplotFacet.ROTATION)) ? ScatterplotFacet.getRotation(o.getString(ScatterplotFacet.ROTATION)) : ScatterplotFacet.NO_ROTATION;
|
||||
|
||||
String color_str = (o.has(ScatterplotFacet.COLOR)) ? o.getString(ScatterplotFacet.COLOR) : "000000";
|
||||
Color color = new Color(Integer.parseInt(color_str,16));
|
||||
|
||||
String columnName_x = o.getString(ScatterplotFacet.X_COLUMN_NAME);
|
||||
String expression_x = (o.has(ScatterplotFacet.X_EXPRESSION)) ? o.getString(ScatterplotFacet.X_EXPRESSION) : "value";
|
||||
|
||||
if (columnName_x.length() > 0) {
|
||||
Column x_column = project.columnModel.getColumnByName(columnName_x);
|
||||
if (x_column != null) {
|
||||
columnIndex_x = x_column.getCellIndex();
|
||||
}
|
||||
} else {
|
||||
columnIndex_x = -1;
|
||||
}
|
||||
|
||||
try {
|
||||
eval_x = MetaParser.parse(expression_x);
|
||||
} catch (ParsingException e) {
|
||||
Gridworks.warn("error parsing expression", e);
|
||||
}
|
||||
|
||||
if (o.has(ScatterplotFacet.FROM_X) && o.has(ScatterplotFacet.TO_X)) {
|
||||
from_x = o.getDouble(ScatterplotFacet.FROM_X);
|
||||
to_x = o.getDouble(ScatterplotFacet.TO_X);
|
||||
}
|
||||
|
||||
String columnName_y = o.getString(ScatterplotFacet.Y_COLUMN_NAME);
|
||||
String expression_y = (o.has(ScatterplotFacet.Y_EXPRESSION)) ? o.getString(ScatterplotFacet.Y_EXPRESSION) : "value";
|
||||
|
||||
if (columnName_y.length() > 0) {
|
||||
Column y_column = project.columnModel.getColumnByName(columnName_y);
|
||||
if (y_column != null) {
|
||||
columnIndex_y = y_column.getCellIndex();
|
||||
}
|
||||
} else {
|
||||
columnIndex_y = -1;
|
||||
}
|
||||
|
||||
try {
|
||||
eval_y = MetaParser.parse(expression_y);
|
||||
} catch (ParsingException e) {
|
||||
Gridworks.warn("error parsing expression", e);
|
||||
}
|
||||
|
||||
if (o.has(ScatterplotFacet.FROM_Y) && o.has(ScatterplotFacet.TO_Y)) {
|
||||
from_y = o.getDouble(ScatterplotFacet.FROM_Y);
|
||||
to_y = o.getDouble(ScatterplotFacet.TO_Y);
|
||||
}
|
||||
|
||||
NumericBinIndex index_x = null;
|
||||
NumericBinIndex index_y = null;
|
||||
|
||||
String col_x_name = o.getString(ScatterplotFacet.X_COLUMN_NAME);
|
||||
Column column_x = project.columnModel.getColumnByName(col_x_name);
|
||||
if (column_x != null) {
|
||||
columnIndex_x = column_x.getCellIndex();
|
||||
index_x = ScatterplotFacet.getBinIndex(project, column_x, eval_x, expression_x);
|
||||
min_x = index_x.getMin();
|
||||
max_x = index_x.getMax();
|
||||
}
|
||||
|
||||
String col_y_name = o.getString(ScatterplotFacet.Y_COLUMN_NAME);
|
||||
Column column_y = project.columnModel.getColumnByName(col_y_name);
|
||||
if (column_y != null) {
|
||||
columnIndex_y = column_y.getCellIndex();
|
||||
index_y = ScatterplotFacet.getBinIndex(project, column_y, eval_y, expression_y);
|
||||
min_y = index_y.getMin();
|
||||
max_y = index_y.getMax();
|
||||
}
|
||||
|
||||
if (index_x != null && index_y != null && index_x.isNumeric() && index_y.isNumeric()) {
|
||||
ScatterplotDrawingRowVisitor drawer = new ScatterplotDrawingRowVisitor(
|
||||
columnIndex_x, columnIndex_y, min_x, max_x, min_y, max_y,
|
||||
size, dim_x, dim_y, rotation, dot, color,
|
||||
from_x, from_y, to_x, to_y
|
||||
);
|
||||
FilteredRows filteredRows = engine.getAllFilteredRows(false);
|
||||
filteredRows.accept(project, drawer);
|
||||
|
||||
ImageIO.write(drawer.getImage(), "png", output);
|
||||
} else {
|
||||
ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR), "png", output);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
713
src/main/webapp/externals/imgareaselect/jquery.imgareaselect.js
vendored
Normal file
713
src/main/webapp/externals/imgareaselect/jquery.imgareaselect.js
vendored
Normal file
@ -0,0 +1,713 @@
|
||||
/*
|
||||
* imgAreaSelect jQuery plugin
|
||||
* version 0.9.2
|
||||
*
|
||||
* Copyright (c) 2008-2010 Michal Wojciechowski (odyniec.net)
|
||||
*
|
||||
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
||||
* and GPL (GPL-LICENSE.txt) licenses.
|
||||
*
|
||||
* http://odyniec.net/projects/imgareaselect/
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
var abs = Math.abs,
|
||||
max = Math.max,
|
||||
min = Math.min,
|
||||
round = Math.round;
|
||||
|
||||
function div() {
|
||||
return $('<div/>');
|
||||
}
|
||||
|
||||
$.imgAreaSelect = function (img, options) {
|
||||
var
|
||||
|
||||
$img = $(img),
|
||||
|
||||
imgLoaded,
|
||||
|
||||
$box = div(),
|
||||
$area = div(),
|
||||
$border = div().add(div()).add(div()).add(div()),
|
||||
$outer = div().add(div()).add(div()).add(div()),
|
||||
$handles = $([]),
|
||||
|
||||
$areaOpera,
|
||||
|
||||
left, top,
|
||||
|
||||
imgOfs,
|
||||
|
||||
imgWidth, imgHeight,
|
||||
|
||||
$parent,
|
||||
|
||||
parOfs,
|
||||
|
||||
zIndex = 0,
|
||||
|
||||
position = 'absolute',
|
||||
|
||||
startX, startY,
|
||||
|
||||
scaleX, scaleY,
|
||||
|
||||
resizeMargin = 10,
|
||||
|
||||
resize,
|
||||
|
||||
minWidth, minHeight, maxWidth, maxHeight,
|
||||
|
||||
aspectRatio,
|
||||
|
||||
shown,
|
||||
|
||||
x1, y1, x2, y2,
|
||||
|
||||
selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 },
|
||||
|
||||
docElem = document.documentElement,
|
||||
|
||||
$p, d, i, o, w, h, adjusted;
|
||||
|
||||
function viewX(x) {
|
||||
return x + imgOfs.left - parOfs.left;
|
||||
}
|
||||
|
||||
function viewY(y) {
|
||||
return y + imgOfs.top - parOfs.top;
|
||||
}
|
||||
|
||||
function selX(x) {
|
||||
return x - imgOfs.left + parOfs.left;
|
||||
}
|
||||
|
||||
function selY(y) {
|
||||
return y - imgOfs.top + parOfs.top;
|
||||
}
|
||||
|
||||
function evX(event) {
|
||||
return event.pageX - parOfs.left;
|
||||
}
|
||||
|
||||
function evY(event) {
|
||||
return event.pageY - parOfs.top;
|
||||
}
|
||||
|
||||
function getSelection(noScale) {
|
||||
var sx = noScale || scaleX, sy = noScale || scaleY;
|
||||
|
||||
return { x1: round(selection.x1 * sx),
|
||||
y1: round(selection.y1 * sy),
|
||||
x2: round(selection.x2 * sx),
|
||||
y2: round(selection.y2 * sy),
|
||||
width: round(selection.x2 * sx) - round(selection.x1 * sx),
|
||||
height: round(selection.y2 * sy) - round(selection.y1 * sy) };
|
||||
}
|
||||
|
||||
function setSelection(x1, y1, x2, y2, noScale) {
|
||||
var sx = noScale || scaleX, sy = noScale || scaleY;
|
||||
|
||||
selection = {
|
||||
x1: round(x1 / sx),
|
||||
y1: round(y1 / sy),
|
||||
x2: round(x2 / sx),
|
||||
y2: round(y2 / sy)
|
||||
};
|
||||
|
||||
selection.width = selection.x2 - selection.x1;
|
||||
selection.height = selection.y2 - selection.y1;
|
||||
}
|
||||
|
||||
function adjust() {
|
||||
if (!$img.width())
|
||||
return;
|
||||
|
||||
imgOfs = { left: round($img.offset().left), top: round($img.offset().top) };
|
||||
|
||||
imgWidth = $img.width() + 1;
|
||||
imgHeight = $img.height() + 1;
|
||||
|
||||
minWidth = options.minWidth || 0;
|
||||
minHeight = options.minHeight || 0;
|
||||
maxWidth = min(options.maxWidth || 1<<24, imgWidth);
|
||||
maxHeight = min(options.maxHeight || 1<<24, imgHeight);
|
||||
|
||||
if ($().jquery == '1.3.2' && position == 'fixed' &&
|
||||
!docElem['getBoundingClientRect'])
|
||||
{
|
||||
imgOfs.top += max(document.body.scrollTop, docElem.scrollTop);
|
||||
imgOfs.left += max(document.body.scrollLeft, docElem.scrollLeft);
|
||||
}
|
||||
|
||||
parOfs = $.inArray($parent.css('position'), ['absolute', 'relative']) + 1 ?
|
||||
{ left: round($parent.offset().left) - $parent.scrollLeft(),
|
||||
top: round($parent.offset().top) - $parent.scrollTop() } :
|
||||
position == 'fixed' ?
|
||||
{ left: $(document).scrollLeft(), top: $(document).scrollTop() } :
|
||||
{ left: 0, top: 0 };
|
||||
|
||||
left = viewX(0);
|
||||
top = viewY(0);
|
||||
|
||||
if (selection.x2 > imgWidth || selection.y2 > imgHeight)
|
||||
doResize();
|
||||
}
|
||||
|
||||
function update(resetKeyPress) {
|
||||
if (!shown) return;
|
||||
|
||||
$box.css({ left: viewX(selection.x1), top: viewY(selection.y1) })
|
||||
.add($area).width(w = selection.width).height(h = selection.height);
|
||||
|
||||
$area.add($border).add($handles).css({ left: 0, top: 0 });
|
||||
|
||||
$border
|
||||
.width(max(w - $border.outerWidth() + $border.innerWidth(), 0))
|
||||
.height(max(h - $border.outerHeight() + $border.innerHeight(), 0));
|
||||
|
||||
$($outer[0]).css({ left: left, top: top,
|
||||
width: selection.x1, height: imgHeight });
|
||||
$($outer[1]).css({ left: left + selection.x1, top: top,
|
||||
width: w, height: selection.y1 });
|
||||
$($outer[2]).css({ left: left + selection.x2, top: top,
|
||||
width: imgWidth - selection.x2, height: imgHeight });
|
||||
$($outer[3]).css({ left: left + selection.x1, top: top + selection.y2,
|
||||
width: w, height: imgHeight - selection.y2 });
|
||||
|
||||
w -= $handles.outerWidth();
|
||||
h -= $handles.outerHeight();
|
||||
|
||||
switch ($handles.length) {
|
||||
case 8:
|
||||
$($handles[4]).css({ left: w / 2 });
|
||||
$($handles[5]).css({ left: w, top: h / 2 });
|
||||
$($handles[6]).css({ left: w / 2, top: h });
|
||||
$($handles[7]).css({ top: h / 2 });
|
||||
case 4:
|
||||
$handles.slice(1,3).css({ left: w });
|
||||
$handles.slice(2,4).css({ top: h });
|
||||
}
|
||||
|
||||
if (resetKeyPress !== false) {
|
||||
if ($.imgAreaSelect.keyPress != docKeyPress)
|
||||
$(document).unbind($.imgAreaSelect.keyPress,
|
||||
$.imgAreaSelect.onKeyPress);
|
||||
|
||||
if (options.keys)
|
||||
$(document)[$.imgAreaSelect.keyPress](
|
||||
$.imgAreaSelect.onKeyPress = docKeyPress);
|
||||
}
|
||||
|
||||
if ($.browser.msie && $border.outerWidth() - $border.innerWidth() == 2) {
|
||||
$border.css('margin', 0);
|
||||
setTimeout(function () { $border.css('margin', 'auto'); }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function doUpdate(resetKeyPress) {
|
||||
adjust();
|
||||
update(resetKeyPress);
|
||||
x1 = viewX(selection.x1); y1 = viewY(selection.y1);
|
||||
x2 = viewX(selection.x2); y2 = viewY(selection.y2);
|
||||
}
|
||||
|
||||
function hide($elem, fn) {
|
||||
options.fadeSpeed ? $elem.fadeOut(options.fadeSpeed, fn) : $elem.hide();
|
||||
|
||||
}
|
||||
|
||||
function areaMouseMove(event) {
|
||||
var x = selX(evX(event)) - selection.x1,
|
||||
y = selY(evY(event)) - selection.y1;
|
||||
|
||||
if (!adjusted) {
|
||||
adjust();
|
||||
adjusted = true;
|
||||
|
||||
$box.one('mouseout', function () { adjusted = false; });
|
||||
}
|
||||
|
||||
resize = '';
|
||||
|
||||
if (options.resizable) {
|
||||
if (y <= resizeMargin)
|
||||
resize = 'n';
|
||||
else if (y >= selection.height - resizeMargin)
|
||||
resize = 's';
|
||||
if (x <= resizeMargin)
|
||||
resize += 'w';
|
||||
else if (x >= selection.width - resizeMargin)
|
||||
resize += 'e';
|
||||
}
|
||||
|
||||
$box.css('cursor', resize ? resize + '-resize' :
|
||||
options.movable ? 'move' : '');
|
||||
if ($areaOpera)
|
||||
$areaOpera.toggle();
|
||||
}
|
||||
|
||||
function docMouseUp(event) {
|
||||
$('body').css('cursor', '');
|
||||
|
||||
if (options.autoHide || selection.width * selection.height == 0)
|
||||
hide($box.add($outer), function () { $(this).hide(); });
|
||||
|
||||
options.onSelectEnd(img, getSelection());
|
||||
|
||||
$(document).unbind('mousemove', selectingMouseMove);
|
||||
$box.mousemove(areaMouseMove);
|
||||
}
|
||||
|
||||
function areaMouseDown(event) {
|
||||
if (event.which != 1) return false;
|
||||
|
||||
adjust();
|
||||
|
||||
if (resize) {
|
||||
$('body').css('cursor', resize + '-resize');
|
||||
|
||||
x1 = viewX(selection[/w/.test(resize) ? 'x2' : 'x1']);
|
||||
y1 = viewY(selection[/n/.test(resize) ? 'y2' : 'y1']);
|
||||
|
||||
$(document).mousemove(selectingMouseMove)
|
||||
.one('mouseup', docMouseUp);
|
||||
$box.unbind('mousemove', areaMouseMove);
|
||||
}
|
||||
else if (options.movable) {
|
||||
startX = left + selection.x1 - evX(event);
|
||||
startY = top + selection.y1 - evY(event);
|
||||
|
||||
$box.unbind('mousemove', areaMouseMove);
|
||||
|
||||
$(document).mousemove(movingMouseMove)
|
||||
.one('mouseup', function () {
|
||||
options.onSelectEnd(img, getSelection());
|
||||
|
||||
$(document).unbind('mousemove', movingMouseMove);
|
||||
$box.mousemove(areaMouseMove);
|
||||
});
|
||||
}
|
||||
else
|
||||
$img.mousedown(event);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function fixAspectRatio(xFirst) {
|
||||
if (aspectRatio)
|
||||
if (xFirst) {
|
||||
x2 = max(left, min(left + imgWidth,
|
||||
x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1)));
|
||||
|
||||
y2 = round(max(top, min(top + imgHeight,
|
||||
y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1))));
|
||||
x2 = round(x2);
|
||||
}
|
||||
else {
|
||||
y2 = max(top, min(top + imgHeight,
|
||||
y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1)));
|
||||
x2 = round(max(left, min(left + imgWidth,
|
||||
x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1))));
|
||||
y2 = round(y2);
|
||||
}
|
||||
}
|
||||
|
||||
function doResize() {
|
||||
x1 = min(x1, left + imgWidth);
|
||||
y1 = min(y1, top + imgHeight);
|
||||
|
||||
if (abs(x2 - x1) < minWidth) {
|
||||
x2 = x1 - minWidth * (x2 < x1 || -1);
|
||||
|
||||
if (x2 < left)
|
||||
x1 = left + minWidth;
|
||||
else if (x2 > left + imgWidth)
|
||||
x1 = left + imgWidth - minWidth;
|
||||
}
|
||||
|
||||
if (abs(y2 - y1) < minHeight) {
|
||||
y2 = y1 - minHeight * (y2 < y1 || -1);
|
||||
|
||||
if (y2 < top)
|
||||
y1 = top + minHeight;
|
||||
else if (y2 > top + imgHeight)
|
||||
y1 = top + imgHeight - minHeight;
|
||||
}
|
||||
|
||||
x2 = max(left, min(x2, left + imgWidth));
|
||||
y2 = max(top, min(y2, top + imgHeight));
|
||||
|
||||
fixAspectRatio(abs(x2 - x1) < abs(y2 - y1) * aspectRatio);
|
||||
|
||||
if (abs(x2 - x1) > maxWidth) {
|
||||
x2 = x1 - maxWidth * (x2 < x1 || -1);
|
||||
fixAspectRatio();
|
||||
}
|
||||
|
||||
if (abs(y2 - y1) > maxHeight) {
|
||||
y2 = y1 - maxHeight * (y2 < y1 || -1);
|
||||
fixAspectRatio(true);
|
||||
}
|
||||
|
||||
selection = { x1: selX(min(x1, x2)), x2: selX(max(x1, x2)),
|
||||
y1: selY(min(y1, y2)), y2: selY(max(y1, y2)),
|
||||
width: abs(x2 - x1), height: abs(y2 - y1) };
|
||||
|
||||
update();
|
||||
|
||||
options.onSelectChange(img, getSelection());
|
||||
}
|
||||
|
||||
function selectingMouseMove(event) {
|
||||
x2 = resize == '' || /w|e/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2);
|
||||
y2 = resize == '' || /n|s/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2);
|
||||
|
||||
doResize();
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
function doMove(newX1, newY1) {
|
||||
x2 = (x1 = newX1) + selection.width;
|
||||
y2 = (y1 = newY1) + selection.height;
|
||||
|
||||
$.extend(selection, { x1: selX(x1), y1: selY(y1), x2: selX(x2),
|
||||
y2: selY(y2) });
|
||||
|
||||
update();
|
||||
|
||||
options.onSelectChange(img, getSelection());
|
||||
}
|
||||
|
||||
function movingMouseMove(event) {
|
||||
x1 = max(left, min(startX + evX(event), left + imgWidth - selection.width));
|
||||
y1 = max(top, min(startY + evY(event), top + imgHeight - selection.height));
|
||||
|
||||
doMove(x1, y1);
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function startSelection() {
|
||||
adjust();
|
||||
|
||||
x2 = x1;
|
||||
y2 = y1;
|
||||
|
||||
doResize();
|
||||
|
||||
resize = '';
|
||||
|
||||
if ($outer.is(':not(:visible)'))
|
||||
$box.add($outer).hide().fadeIn(options.fadeSpeed||0);
|
||||
|
||||
shown = true;
|
||||
|
||||
$(document).unbind('mouseup', cancelSelection)
|
||||
.mousemove(selectingMouseMove).one('mouseup', docMouseUp);
|
||||
$box.unbind('mousemove', areaMouseMove);
|
||||
|
||||
options.onSelectStart(img, getSelection());
|
||||
}
|
||||
|
||||
function cancelSelection() {
|
||||
$(document).unbind('mousemove', startSelection);
|
||||
hide($box.add($outer));
|
||||
|
||||
selection = { x1: selX(x1), y1: selY(y1), x2: selX(x1), y2: selY(y1),
|
||||
width: 0, height: 0 };
|
||||
|
||||
options.onSelectChange(img, getSelection());
|
||||
options.onSelectEnd(img, getSelection());
|
||||
}
|
||||
|
||||
function imgMouseDown(event) {
|
||||
if (event.which != 1 || $outer.is(':animated')) return false;
|
||||
|
||||
adjust();
|
||||
startX = x1 = evX(event);
|
||||
startY = y1 = evY(event);
|
||||
|
||||
$(document).one('mousemove', startSelection)
|
||||
.one('mouseup', cancelSelection);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function windowResize() {
|
||||
doUpdate(false);
|
||||
}
|
||||
|
||||
function imgLoad() {
|
||||
imgLoaded = true;
|
||||
|
||||
setOptions(options = $.extend({
|
||||
classPrefix: 'imgareaselect',
|
||||
movable: true,
|
||||
resizable: true,
|
||||
parent: 'body',
|
||||
onInit: function () {},
|
||||
onSelectStart: function () {},
|
||||
onSelectChange: function () {},
|
||||
onSelectEnd: function () {}
|
||||
}, options));
|
||||
|
||||
$box.add($outer).css({ visibility: '' });
|
||||
|
||||
if (options.show) {
|
||||
shown = true;
|
||||
adjust();
|
||||
update();
|
||||
$box.add($outer).hide().fadeIn(options.fadeSpeed||0);
|
||||
}
|
||||
|
||||
setTimeout(function () { options.onInit(img, getSelection()); }, 0);
|
||||
}
|
||||
|
||||
var docKeyPress = function(event) {
|
||||
var k = options.keys, d, t, key = event.keyCode;
|
||||
|
||||
d = !isNaN(k.alt) && (event.altKey || event.originalEvent.altKey) ? k.alt :
|
||||
!isNaN(k.ctrl) && event.ctrlKey ? k.ctrl :
|
||||
!isNaN(k.shift) && event.shiftKey ? k.shift :
|
||||
!isNaN(k.arrows) ? k.arrows : 10;
|
||||
|
||||
if (k.arrows == 'resize' || (k.shift == 'resize' && event.shiftKey) ||
|
||||
(k.ctrl == 'resize' && event.ctrlKey) ||
|
||||
(k.alt == 'resize' && (event.altKey || event.originalEvent.altKey)))
|
||||
{
|
||||
switch (key) {
|
||||
case 37:
|
||||
d = -d;
|
||||
case 39:
|
||||
t = max(x1, x2);
|
||||
x1 = min(x1, x2);
|
||||
x2 = max(t + d, x1);
|
||||
fixAspectRatio();
|
||||
break;
|
||||
case 38:
|
||||
d = -d;
|
||||
case 40:
|
||||
t = max(y1, y2);
|
||||
y1 = min(y1, y2);
|
||||
y2 = max(t + d, y1);
|
||||
fixAspectRatio(true);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
doResize();
|
||||
}
|
||||
else {
|
||||
x1 = min(x1, x2);
|
||||
y1 = min(y1, y2);
|
||||
|
||||
switch (key) {
|
||||
case 37:
|
||||
doMove(max(x1 - d, left), y1);
|
||||
break;
|
||||
case 38:
|
||||
doMove(x1, max(y1 - d, top));
|
||||
break;
|
||||
case 39:
|
||||
doMove(x1 + min(d, imgWidth - selX(x2)), y1);
|
||||
break;
|
||||
case 40:
|
||||
doMove(x1, y1 + min(d, imgHeight - selY(y2)));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
function styleOptions($elem, props) {
|
||||
for (option in props)
|
||||
if (options[option] !== undefined)
|
||||
$elem.css(props[option], options[option]);
|
||||
}
|
||||
|
||||
function setOptions(newOptions) {
|
||||
if (newOptions.parent)
|
||||
($parent = $(newOptions.parent)).append($box.add($outer));
|
||||
|
||||
$.extend(options, newOptions);
|
||||
|
||||
adjust();
|
||||
|
||||
if (newOptions.handles != null) {
|
||||
$handles.remove();
|
||||
$handles = $([]);
|
||||
|
||||
i = newOptions.handles ? newOptions.handles == 'corners' ? 4 : 8 : 0;
|
||||
|
||||
while (i--)
|
||||
$handles = $handles.add(div());
|
||||
|
||||
$handles.addClass(options.classPrefix + '-handle').css({
|
||||
position: 'absolute',
|
||||
fontSize: 0,
|
||||
zIndex: zIndex + 1 || 1
|
||||
});
|
||||
|
||||
if (!parseInt($handles.css('width')))
|
||||
$handles.width(5).height(5);
|
||||
|
||||
if (o = options.borderWidth)
|
||||
$handles.css({ borderWidth: o, borderStyle: 'solid' });
|
||||
|
||||
styleOptions($handles, { borderColor1: 'border-color',
|
||||
borderColor2: 'background-color',
|
||||
borderOpacity: 'opacity' });
|
||||
}
|
||||
|
||||
scaleX = options.imageWidth / imgWidth || 1;
|
||||
scaleY = options.imageHeight / imgHeight || 1;
|
||||
|
||||
if (newOptions.x1 != null) {
|
||||
setSelection(newOptions.x1, newOptions.y1, newOptions.x2,
|
||||
newOptions.y2);
|
||||
newOptions.show = !newOptions.hide;
|
||||
}
|
||||
|
||||
if (newOptions.keys)
|
||||
options.keys = $.extend({ shift: 1, ctrl: 'resize' },
|
||||
newOptions.keys);
|
||||
|
||||
$outer.addClass(options.classPrefix + '-outer');
|
||||
$area.addClass(options.classPrefix + '-selection');
|
||||
for (i = 0; i++ < 4;)
|
||||
$($border[i-1]).addClass(options.classPrefix + '-border' + i);
|
||||
|
||||
styleOptions($area, { selectionColor: 'background-color',
|
||||
selectionOpacity: 'opacity' });
|
||||
styleOptions($border, { borderOpacity: 'opacity',
|
||||
borderWidth: 'border-width' });
|
||||
styleOptions($outer, { outerColor: 'background-color',
|
||||
outerOpacity: 'opacity' });
|
||||
if (o = options.borderColor1)
|
||||
$($border[0]).css({ borderStyle: 'solid', borderColor: o });
|
||||
if (o = options.borderColor2)
|
||||
$($border[1]).css({ borderStyle: 'dashed', borderColor: o });
|
||||
|
||||
$box.append($area.add($border).add($handles).add($areaOpera));
|
||||
|
||||
if ($.browser.msie) {
|
||||
if (o = $outer.css('filter').match(/opacity=([0-9]+)/))
|
||||
$outer.css('opacity', o[1]/100);
|
||||
if (o = $border.css('filter').match(/opacity=([0-9]+)/))
|
||||
$border.css('opacity', o[1]/100);
|
||||
}
|
||||
|
||||
if (newOptions.hide)
|
||||
hide($box.add($outer));
|
||||
else if (newOptions.show && imgLoaded) {
|
||||
shown = true;
|
||||
$box.add($outer).fadeIn(options.fadeSpeed||0);
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
aspectRatio = (d = (options.aspectRatio || '').split(/:/))[0] / d[1];
|
||||
|
||||
if (options.disable || options.enable === false) {
|
||||
$box.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown);
|
||||
$img.add($outer).unbind('mousedown', imgMouseDown);
|
||||
$(window).unbind('resize', windowResize);
|
||||
}
|
||||
else if (options.enable || options.disable === false) {
|
||||
if (options.resizable || options.movable)
|
||||
$box.mousemove(areaMouseMove).mousedown(areaMouseDown);
|
||||
|
||||
if (!options.persistent)
|
||||
$img.add($outer).mousedown(imgMouseDown);
|
||||
|
||||
$(window).resize(windowResize);
|
||||
}
|
||||
|
||||
options.enable = options.disable = undefined;
|
||||
}
|
||||
|
||||
this.remove = function () {
|
||||
$img.unbind('mousedown', imgMouseDown);
|
||||
$box.add($outer).remove();
|
||||
};
|
||||
|
||||
this.getOptions = function () { return options; };
|
||||
|
||||
this.setOptions = setOptions;
|
||||
|
||||
this.getSelection = getSelection;
|
||||
|
||||
this.setSelection = setSelection;
|
||||
|
||||
this.update = doUpdate;
|
||||
|
||||
$p = $img;
|
||||
|
||||
while ($p.length) {
|
||||
zIndex = max(zIndex,
|
||||
!isNaN($p.css('z-index')) ? $p.css('z-index') : zIndex);
|
||||
if ($p.css('position') == 'fixed')
|
||||
position = 'fixed';
|
||||
|
||||
$p = $p.parent(':not(body)');
|
||||
}
|
||||
|
||||
zIndex = options.zIndex || zIndex;
|
||||
|
||||
if ($.browser.msie)
|
||||
$img.attr('unselectable', 'on');
|
||||
|
||||
$.imgAreaSelect.keyPress = $.browser.msie ||
|
||||
$.browser.safari ? 'keydown' : 'keypress';
|
||||
|
||||
if ($.browser.opera)
|
||||
$areaOpera = div().css({ width: '100%', height: '100%',
|
||||
position: 'absolute', zIndex: zIndex + 2 || 2 });
|
||||
|
||||
$box.add($outer).css({ visibility: 'hidden', position: position,
|
||||
overflow: 'hidden', zIndex: zIndex || '0' });
|
||||
$box.css({ zIndex: zIndex + 2 || 2 });
|
||||
$area.add($border).css({ position: 'absolute', fontSize: 0 });
|
||||
|
||||
img.complete || img.readyState == 'complete' || !$img.is('img') ?
|
||||
imgLoad() : $img.one('load', imgLoad);
|
||||
};
|
||||
|
||||
$.fn.imgAreaSelect = function (options) {
|
||||
options = options || {};
|
||||
|
||||
this.each(function () {
|
||||
if ($(this).data('imgAreaSelect')) {
|
||||
if (options.remove) {
|
||||
$(this).data('imgAreaSelect').remove();
|
||||
$(this).removeData('imgAreaSelect');
|
||||
}
|
||||
else
|
||||
$(this).data('imgAreaSelect').setOptions(options);
|
||||
}
|
||||
else if (!options.remove) {
|
||||
if (options.enable === undefined && options.disable === undefined)
|
||||
options.enable = true;
|
||||
|
||||
$(this).data('imgAreaSelect', new $.imgAreaSelect(this, options));
|
||||
}
|
||||
});
|
||||
|
||||
if (options.instance)
|
||||
return $(this).data('imgAreaSelect');
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
})(jQuery);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -25,11 +25,16 @@ ScatterplotDialog.prototype._createDialog = function() {
|
||||
'<tr>' +
|
||||
'<td>' +
|
||||
'<span class="clustering-dialog-controls">Plot type: <select bind="plotSelector">' +
|
||||
'<option selected="true">linear</option>' +
|
||||
'<option>log-log</option>' +
|
||||
'<option selected="true" value="lin">linear</option>' +
|
||||
'<option value="log">log-log</option>' +
|
||||
'</select></span>' +
|
||||
'<span class="clustering-dialog-controls">Plot Size: <input bind="plotSize" type="test" size="2" value=""> px</span>' +
|
||||
'<span class="clustering-dialog-controls">Dot Size: <input bind="dotSize" type="test" size="2" value=""> px</span>' +
|
||||
'<span class="clustering-dialog-controls">Rotation: <select bind="rotationSelector">' +
|
||||
'<option selected="true" value="none">none</option>' +
|
||||
'<option value="cw">45° clockwise</option>' +
|
||||
'<option value="ccw">45° counter-clockwise</option>' +
|
||||
'</select></span>' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
@ -44,15 +49,15 @@ ScatterplotDialog.prototype._createDialog = function() {
|
||||
this._elmts = DOM.bind(html);
|
||||
|
||||
this._elmts.plotSelector.change(function() {
|
||||
var selection = $(this).find("option:selected").text();
|
||||
if (selection == 'linear') {
|
||||
self._plot_method = "lin";
|
||||
} else if (selection === 'log-log') {
|
||||
self._plot_method = "log";
|
||||
}
|
||||
self._plot_method = $(this).find("option:selected").attr("value");
|
||||
self._renderMatrix();
|
||||
});
|
||||
|
||||
this._elmts.rotationSelector.change(function() {
|
||||
self._rotation = $(this).find("option:selected").attr("value");
|
||||
self._renderMatrix();
|
||||
});
|
||||
|
||||
this._elmts.plotSize.change(function() {
|
||||
try {
|
||||
self._plot_size = parseInt($(this).val())
|
||||
@ -119,10 +124,11 @@ ScatterplotDialog.prototype._renderMatrix = function() {
|
||||
var plotter_params = {
|
||||
'cx' : cx,
|
||||
'cy' : cy,
|
||||
'w' : self._plot_size * 3,
|
||||
'h' : self._plot_size * 3,
|
||||
'l' : self._plot_size,
|
||||
'dot': self._dot_size,
|
||||
'dim': self._plot_method
|
||||
'dim_x': self._plot_method,
|
||||
'dim_y': self._plot_method,
|
||||
'r': self._rotation
|
||||
};
|
||||
var params = {
|
||||
project: theProject.id,
|
||||
@ -157,12 +163,15 @@ ScatterplotDialog.prototype._renderMatrix = function() {
|
||||
container.find("a").click(function() {
|
||||
var options = {
|
||||
"name" : $(this).attr("title"),
|
||||
"x_columnName" : $(this).attr("cx"),
|
||||
"y_columnName" : $(this).attr("cy"),
|
||||
"x_expression" : "value",
|
||||
"y_expression" : "value",
|
||||
"cx" : $(this).attr("cx"),
|
||||
"cy" : $(this).attr("cy"),
|
||||
"l" : 120,
|
||||
"ex" : "value",
|
||||
"ey" : "value",
|
||||
"dot" : self._dot_size,
|
||||
"dim" : self._plot_method
|
||||
"dim_x" : self._plot_method,
|
||||
"dim_y" : self._plot_method,
|
||||
'r': self._rotation
|
||||
};
|
||||
ui.browsingEngine.addFacet("scatterplot", options);
|
||||
//self._dismiss();
|
||||
|
@ -3,17 +3,16 @@ function ScatterplotFacet(div, config, options) {
|
||||
this._config = config;
|
||||
this._options = options;
|
||||
|
||||
this._from_x = ("from_x" in this._config) ? this._config.from_x : null;
|
||||
this._to_x = ("to_x" in this._config) ? this._config.to_x : null;
|
||||
this._from_y = ("from_y" in this._config) ? this._config.from_y : null;
|
||||
this._to_y = ("to_y" in this._config) ? this._config.to_y : null;
|
||||
|
||||
this._error = false;
|
||||
this._initializedUI = false;
|
||||
}
|
||||
|
||||
ScatterplotFacet.prototype.reset = function() {
|
||||
// TODO
|
||||
delete this._config.from_x;
|
||||
delete this._config.from_y;
|
||||
delete this._config.to_x;
|
||||
delete this._config.to_y;
|
||||
this._plotImg.imgAreaSelect({ hide : true});
|
||||
};
|
||||
|
||||
ScatterplotFacet.reconstruct = function(div, uiState) {
|
||||
@ -30,18 +29,8 @@ ScatterplotFacet.prototype.getUIState = function() {
|
||||
};
|
||||
|
||||
ScatterplotFacet.prototype.getJSON = function() {
|
||||
var o = {
|
||||
type: "scatterplot",
|
||||
name: this._config.name,
|
||||
x_columnName : this._config.x_columnName,
|
||||
y_columnName : this._config.y_columnName,
|
||||
x_expression: this._config.x_expression,
|
||||
y_expression: this._config.y_expression,
|
||||
dot: this._config.dot,
|
||||
dim: this._config.dim,
|
||||
};
|
||||
|
||||
return o;
|
||||
this._config.type = "scatterplot";
|
||||
return this._config;
|
||||
};
|
||||
|
||||
ScatterplotFacet.prototype.hasSelection = function() {
|
||||
@ -70,36 +59,60 @@ ScatterplotFacet.prototype._initializeUI = function() {
|
||||
|
||||
var bodyDiv = $('<div></div>').addClass("facet-scatterplot-body").appendTo(container);
|
||||
|
||||
var params = {
|
||||
project: theProject.id,
|
||||
engine: JSON.stringify(ui.browsingEngine.getJSON()),
|
||||
plotter: JSON.stringify(this._config)
|
||||
};
|
||||
var url = "/command/get-scatterplot?" + $.param(params);
|
||||
|
||||
this._messageDiv = $('<div>').text("Loading...").addClass("facet-scatterplot-message").appendTo(bodyDiv);
|
||||
this._plotDiv = $('<div>').addClass("facet-scatterplot-plot").appendTo(bodyDiv);
|
||||
this._plotImg = $('<img>')
|
||||
.addClass("facet-scatterplot-image")
|
||||
.attr("src",url)
|
||||
.attr("width", this._config.l)
|
||||
.attr("height", this._config.l)
|
||||
.imgAreaSelect({
|
||||
handles: false,
|
||||
fadeSpeed: 70,
|
||||
onSelectEnd: function(elmt, selection) {
|
||||
if (selection.height == 0 || selection.width == 0) {
|
||||
self.reset();
|
||||
} else {
|
||||
self._config.from_x = selection.x1;
|
||||
self._config.to_x = selection.x2 - 2;
|
||||
self._config.from_y = self._config.l - selection.y2 + 2;
|
||||
self._config.to_y = self._config.l - selection.y1 - 1;
|
||||
}
|
||||
self._updateRest();
|
||||
}
|
||||
}).appendTo(this._plotDiv);
|
||||
this._statusDiv = $('<div>').addClass("facet-scatterplot-status").appendTo(bodyDiv);
|
||||
|
||||
this._plot = new ScatterplotWidget(this._plotDiv, this._config);
|
||||
};
|
||||
|
||||
ScatterplotFacet.prototype.updateState = function(data) {
|
||||
if ("x_min" in data && "x_max" in data && "x_max" in data && "x_min" in data) {
|
||||
if ("min_x" in data && "max_x" in data && "max_x" in data && "min_x" in data) {
|
||||
this._error = false;
|
||||
|
||||
this._config.x_min = data.x_min;
|
||||
this._config.x_max = data.x_max;
|
||||
this._config.y_min = data.y_min;
|
||||
this._config.y_max = data.y_max;
|
||||
this._config.min_x = data.min_x;
|
||||
this._config.max_x = data.max_x;
|
||||
this._config.min_y = data.min_y;
|
||||
this._config.max_y = data.max_y;
|
||||
|
||||
this._from_x = Math.max(data.from_x, this._config.x_min);
|
||||
this._config.from_x = Math.max(data.from_x, this._config.min_x);
|
||||
if ("to_x" in data) {
|
||||
this._to_x = Math.min(data.to_x, this._config.x_max);
|
||||
this._config.to_x = Math.min(data.to_x, this._config.max_x);
|
||||
} else {
|
||||
this._to_x = data.x_max;
|
||||
this._config.to_x = data.max_x;
|
||||
}
|
||||
|
||||
this._from_y = Math.max(data.from_y, this._config.x_min);
|
||||
this._config.from_y = Math.max(data.from_y, this._config.min_x);
|
||||
if ("to_y" in data) {
|
||||
this._to_y = Math.min(data.to_y, this._config.x_max);
|
||||
this._config.to_y = Math.min(data.to_y, this._config.max_x);
|
||||
} else {
|
||||
this._to_y = data.x_max;
|
||||
this._config.to_y = data.max_x;
|
||||
}
|
||||
|
||||
} else {
|
||||
this._error = true;
|
||||
this._errorMessage = "error" in data ? data.error : "Unknown error.";
|
||||
@ -124,17 +137,6 @@ ScatterplotFacet.prototype.render = function() {
|
||||
this._messageDiv.hide();
|
||||
this._plotDiv.show();
|
||||
this._statusDiv.show();
|
||||
|
||||
this._plot.update(
|
||||
this._config.x_min,
|
||||
this._config.x_max,
|
||||
this._x_from,
|
||||
this._x_to,
|
||||
this._config.y_min,
|
||||
this._config.y_max,
|
||||
this._y_from,
|
||||
this._y_to
|
||||
);
|
||||
};
|
||||
|
||||
ScatterplotFacet.prototype._remove = function() {
|
||||
|
@ -1,125 +0,0 @@
|
||||
function ScatterplotWidget(elmt, options) {
|
||||
this._elmt = elmt;
|
||||
this._options = options;
|
||||
|
||||
this._plotter = {
|
||||
'cx' : options.x_columnName,
|
||||
'cy' : options.y_columnName,
|
||||
'xe' : options.x_expression,
|
||||
'ye' : options.y_expression,
|
||||
'dot': options.dot,
|
||||
'dim': options.dim
|
||||
};
|
||||
|
||||
this._range = null;
|
||||
this._highlight = null;
|
||||
|
||||
this._initializeUI();
|
||||
}
|
||||
|
||||
ScatterplotWidget.prototype.highlight = function(from_x, to_x, from_y, to_y) {
|
||||
this._highlight = { from_x: from_x, to_x: to_x, from_y: from_y, to_y: to_y };
|
||||
this._update();
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype.update = function(x_min, x_max, x_from, x_to, y_min, y_max, y_from, y_to) {
|
||||
if (typeof x_min == "undefined" || typeof y_min == "undefined") {
|
||||
this._range = null;
|
||||
this._highlight = null;
|
||||
|
||||
this._elmt.hide();
|
||||
} else {
|
||||
this._range = { x_min: x_min, x_max: x_max, y_min: y_min, y_max: y_max };
|
||||
|
||||
if (typeof from_x != "undefined" && typeof to_x != "undefined" &&
|
||||
typeof from_y != "undefined" && typeof to_y != "undefined")
|
||||
{
|
||||
this._highlight = { from_x: from_x, to_x: to_x, from_y: from_y, to_y: to_y };
|
||||
}
|
||||
|
||||
this._update();
|
||||
}
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._update = function() {
|
||||
if (this._highlight !== null) {
|
||||
this._highlight.from_x = Math.max(this._highlight.from_x, this._range.x_min);
|
||||
this._highlight.to_x = Math.min(this._highlight.to_x, this._range.max_x);
|
||||
this._highlight.from_y = Math.max(this._highlight.from_y, this._range.y_min);
|
||||
this._highlight.to_y = Math.min(this._highlight.to_y, this._range.max_y);
|
||||
}
|
||||
|
||||
this._elmt.show();
|
||||
this._resize();
|
||||
this._render();
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._initializeUI = function() {
|
||||
self = this;
|
||||
|
||||
this._elmt
|
||||
.empty()
|
||||
.hide()
|
||||
.addClass("scatterplot-widget")
|
||||
.html('<canvas bind="canvas"></canvas>');
|
||||
|
||||
this._elmts = DOM.bind(this._elmt);
|
||||
this._elmts.canvas.imgAreaSelect({
|
||||
handles: false,
|
||||
fadeSpeed: 70,
|
||||
onSelectEnd: function(elmt, selection) {
|
||||
self.highlight(
|
||||
selection.x1,
|
||||
selection.x2,
|
||||
self._plotter.h - selection.y2,
|
||||
self._plotter.h - selection.y1
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._resize = function() {
|
||||
this._plotter.w = this._elmts.canvas.width();
|
||||
this._plotter.h = ("height" in this._options) ? this._options.height : this._plotter.w;
|
||||
this._elmts.canvas.attr("width", this._plotter.w);
|
||||
this._elmts.canvas.attr("height", this._plotter.h);
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._render = function() {
|
||||
var self = this;
|
||||
var options = this._options;
|
||||
|
||||
var canvas = this._elmts.canvas[0];
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.save();
|
||||
|
||||
var img = new Image();
|
||||
img.onload = function(){
|
||||
ctx.drawImage(img,0,0);
|
||||
if (self._highlight != null) {
|
||||
var img2 = new Image();
|
||||
img2.onload = function(){
|
||||
ctx.drawImage(img2,0,0);
|
||||
ctx.restore();
|
||||
}
|
||||
self._plotter.color = "000088";
|
||||
console.log(self._plotter);
|
||||
img2.src = self._get_image_url(self._plotter);
|
||||
}
|
||||
}
|
||||
self._plotter.color = "000000";
|
||||
console.log(self._plotter);
|
||||
img.src = self._get_image_url(self._plotter);
|
||||
};
|
||||
|
||||
ScatterplotWidget.prototype._get_image_url = function(o) {
|
||||
var params = {
|
||||
project: theProject.id,
|
||||
engine: JSON.stringify(ui.browsingEngine.getJSON()),
|
||||
plotter: JSON.stringify(o)
|
||||
}
|
||||
return "/command/get-scatterplot?" + $.param(params);
|
||||
};
|
@ -38,9 +38,6 @@ li.facet-container {
|
||||
-moz-border-radius: 7px;
|
||||
-webkit-border-radius: 7px;
|
||||
border-radius: 7px 7px;
|
||||
|
||||
-moz-border-radius-bottomright: 0px;
|
||||
-webkit-border-bottom-right-radius: 0px;
|
||||
}
|
||||
|
||||
.facet-title {
|
||||
@ -162,3 +159,8 @@ img.facet-choice-link {
|
||||
border: 1px solid #ccc;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.facet-scatterplot-image {
|
||||
border: 1px solid #f0f0f0;
|
||||
margin: 0.5em 0.8em;
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
.scatterplot-widget {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.scatterplot-widget canvas {
|
||||
width: 120px;
|
||||
border: 1px solid #f0f0f0;
|
||||
margin: 0.5em 0.8em;
|
||||
}
|
Loading…
Reference in New Issue
Block a user