I have a reproducible example taken from https://bl.ocks.org/timelyportfolio/5ab450e90ee510f4df9758b9ec5a8ad0.
library(sf)
library(plotly)
library(leaflet)
library(crosstalk)
library(htmltools)
boroughs<- st_read("http://services5.arcgis.com/GfwWNkhOj9bNBqoJ/arcgis/rest/services/nybb/FeatureServer/0/query?where=1=1&outFields=*&outSR=4326&f=geojson")
boroughs$x <- seq(1:5)
boroughs$y <- seq(2,10,2)
boroughs_sd <- SharedData$new(
boroughs,
key=~BoroCode,
# provide explicit group so we can easily refer to this later
group = "boroughs"
)
map <- leaflet(boroughs_sd) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(
data=boroughs,
layerId = ~BoroCode,
color = "#444444",
weight = 1,
smoothFactor = 0.5,
opacity = 1.0,
fillOpacity = 0.5,
fillColor = ~colorQuantile("Greens", x)(x)#,
# turn off highlight since it interferes with selection styling
# if careful with styling could have both highlight and select
# highlightOptions = highlightOptions(color = "white", weight = 2)
)
# borrow from https://github.com/r-spatial/mapedit/blob/master/R/query.R#L73-L132
# to select/deselect features but instead of Shiny.onInputChange
# use crosstalk to manage state
add_select_script <- function(lf, styleFalse, styleTrue, ns="") {
## check for existing onRender jsHook?
htmlwidgets::onRender(
lf,
sprintf(
"
function(el,x) {
var lf = this;
var style_obj = {
'false': %s,
'true': %s
}
// instead of shiny input as our state manager
// use crosstalk
if(crosstalk) {
var ct_sel = new crosstalk.SelectionHandle()
ct_sel.setGroup('boroughs')
ct_sel.on('change', function(x){
if(x.sender !== ct_sel) { //ignore select from this map
lf.eachLayer(function(lyr){
if(lyr.options && lyr.options.layerId) {
var id = String(lyr.options.layerId)
if(
!x.value ||
(Array.isArray(x.value) && x.value.indexOf(id) === -1)
) {
toggle_state(lyr, false)
toggle_style(lyr, style_obj.false)
}
if(Array.isArray(x.value) && x.value.indexOf(id) > -1) {
toggle_state(lyr, true)
toggle_style(lyr, style_obj.true)
}
}
})
}
})
}
// define our functions for toggling
function toggle_style(layer, style_obj) {
layer.setStyle(style_obj);
};
function toggle_state(layer, selected, init) {
if(typeof(selected) !== 'undefined') {
layer._mapedit_selected = selected;
} else {
selected = !layer._mapedit_selected;
layer._mapedit_selected = selected;
}
if(typeof(Shiny) !== 'undefined' && Shiny.onInputChange && !init) {
Shiny.onInputChange(
'%s-mapedit_selected',
{
'group': layer.options.group,
'id': layer.options.layerId,
'selected': selected
}
)
}
if(ct_sel) {
var ct_values = ct_sel.value
var id = String(layer.options.layerId)
if(selected) {
if(!ct_values) {
ct_sel.set([id])
}
if(Array.isArray(ct_values) && ct_values.indexOf(id) === -1) {
ct_sel.set(ct_values.concat(id))
}
}
if(ct_values && !selected) {
ct_values.length > 1 ?
ct_sel.set(
ct_values.filter(function(d) {
return d !== id
})
) :
ct_sel.set(null) // select all if nothing selected
}
}
return selected;
};
// set up click handler on each layer with a group name
lf.eachLayer(function(lyr){
if(lyr.on && lyr.options && lyr.options.layerId) {
// start with all unselected ?
toggle_state(lyr, false, init=true);
toggle_style(lyr, style_obj[lyr._mapedit_selected]);
lyr.on('mouseover',function(e){
var selected = toggle_state(e.target);
toggle_style(e.target, style_obj[String(selected)]);
});
}
});
}
",
jsonlite::toJSON(styleFalse, auto_unbox=TRUE),
jsonlite::toJSON(styleTrue, auto_unbox=TRUE),
ns
)
)
}
browsable(
tagList(
tags$div(
style = "float:left; width: 49%;",
add_select_script(
map,
styleFalse = list(fillOpacity = 0.2, weight = 1, opacity = 0.4, color="black"),
styleTrue = list(fillOpacity = 0.7, weight = 3, opacity = 0.7, color="blue")
)
),
tags$div(
style = "float:left; width: 49%;",
plot_ly(boroughs_sd, x = ~x, y = ~y) %>%
add_markers(alpha = 0.5,text = ~paste('Borough: ', BoroName)) %>%
highlight(on = "plotly_selected")
)
)
)
I made a minor change to the code from it's original source so that polygons are highlighted on mouseover rather than click.
My experience with JavaScript is pretty minimal. What do I need to change so that selection of polygons is not persistent (i.e. highlight style only changes when on mouseover and does not remain after the mouse has left that particular polygon)?
I suggest to change the following part of code
lyr.on('mouseover',function(e){
var selected = toggle_state(e.target);
toggle_style(e.target, style_obj[String(selected)]);
});
with
lyr.on('mouseover',function(e) {
var selected = toggle_state(e.target, true);
toggle_style(e.target, style_obj[String(selected)]);
});
lyr.on('mouseout',function(e) {
var selected = toggle_state(e.target, false);
toggle_style(e.target, style_obj[String(selected)]);
});
It works on my R.
Related
I have an app where I am trying to change a point's size or color or symbol.
The point being the object that the user has clicked.
Clicking a point creates a popup in my program that shows another dataset linked to the ID value in a column belonging to the rownumber belonging to the point clicked. I included the flow of events in the demo app (without popups) for the click event.
I'm trying to change the point based on the answer here for a plotly 2d scatter plot. However, applying the code to my 3d plot doesn't seem to work.
A little extra background info: i'm building a program to analyse 3d scatter data and my app contains several of these 3D plots
Does anyone know how to make this work?
The app below contains the code for both a 2d (commented) and 3d plot object to show the working and non working situation and is a direct modification of the code given by #Maximilian Peters
Thank you for any help!
bonus question: Assuming we can make it work for the 3dplot, I would also like to figure out how to change the JavaScript code to change a point based on a number stored in a reactive variable (i.e. values$activepoint) rather than from a click event since I will allow the user to cycle through points with a <- and -> button that changes the point ID we are retrieving the additional info from.
library(shiny)
library(plotly)
library(htmlwidgets)
ui <- fluidPage(
plotlyOutput("plot"),
textOutput('messageNr')
)
javascript <- "
function(el, x){
el.on('plotly_click', function(data) {
colors = [];
var base_color = document.getElementsByClassName('legendpoints')[data.points[0].curveNumber].getElementsByTagName('path')[0].style['stroke']
for (var i = 0; i < data.points[0].data.x.length; i += 1) {
colors.push(base_color)
};
colors[data.points[0].pointNumber] = '#000000';
Plotly.restyle(el,
{'marker':{color: colors}},
[data.points[0].curveNumber]
);
//make sure all the other traces get back their original color
for (i = 0; i < document.getElementsByClassName('plotly')[0].data.length; i += 1) {
if (i != data.points[0].curveNumber) {
colors = [];
base_color = document.getElementsByClassName('legendpoints')[i].getElementsByTagName('path')[0].style['stroke'];
for (var p = 0; p < document.getElementsByClassName('plotly')[0].data[i].x.length; p += 1) {
colors.push(base_color);
}
Plotly.restyle(el,
{'marker':{color: colors}},
[i]);
}
};
});
}"
server <- function(input, output, session) {
row.names(mtcars) <- 1:nrow(mtcars)
colorscale <- c("blue", "red", "yellow")
values <- reactiveValues()
output$plot <- renderPlotly({
values$point <- event_data("plotly_click", source = "select")
plot_ly(mtcars,
x = ~mpg,
y = ~cyl,
z = ~wt,
type = "scatter3d",
color = as.factor(mtcars$gear),
colors = colorscale,
mode = "markers",
source = "select",
showlegend = F)%>%
add_markers() %>% onRender(javascript)
} )
observeEvent(values$point, {
values$row <- as.numeric(values$point$pointNumber) +1
values$ID <- rownames(mtcars)[values$row]
### the values$ID is what I use to look up the corresponding dataset in other dataframes containing the detailed info of a datapoint in the
### summary data set that is used to create the real scatter3d plots in which the user clicks.
output$messageNr <- renderText(values$ID)
})
}
# server <- function(input, output, session) {
#
# nms <- row.names(mtcars)
#
# output$plot <- renderPlotly({
# p <- ggplot(mtcars, aes(x = mpg, y = wt, col = as.factor(cyl))) +
# geom_point()
# ggplotly(p) %>% onRender(javascript)
#
# })
# }
shinyApp(ui, server)
You could add a trace just for highlighting the point, change the location of the single point in response to a Javascript eventListener.
library(shiny)
library(plotly)
library(htmlwidgets)
ui <- fluidPage(
plotlyOutput("plot"),
textOutput('messageNr')
)
javascript <- "
function(el, x) {
el.on('plotly_click', function(data) {
var highlight_trace = el.data.length - 1;
//the coordinates of the point which was clicked on
//is found in data
var newPoint = {x: data.points[0].x,
y: data.points[0].y,
z: data.points[0].z};
//update the plot data and redraw it
if (el.data[highlight_trace].x[0] != newPoint.x ||
el.data[highlight_trace].y[0] != newPoint.y ||
el.data[highlight_trace].z[0] != newPoint.z) {
el.data[highlight_trace].x[0] = newPoint.x;
el.data[highlight_trace].y[0] = newPoint.y
el.data[highlight_trace].z[0] = newPoint.z
Plotly.redraw(el);
}
})
}
"
server <- function(input, output, session) {
output$plot <- renderPlotly(
{
p <- plot_ly()
p <- add_trace(p,
data = mtcars,
x = ~mpg,
y = ~cyl,
z = ~wt,
color = as.factor(mtcars$gear),
type = 'scatter3d',
mode = "markers")
p <- add_trace(p,
x = c(20),
y = c(5),
z = c(4),
name = 'highlight',
type = 'scatter3d',
mode = 'markers',
marker = list(size = 15,
opacity = 0.5)) %>% onRender(javascript)
p
}
)
}
shinyApp(ui, server)
el is the JavaScript element where your plot is stored
'el.data' is where Plotly stores the data for your plot
the if block makes sure that the graph is only redrawn if a new point is clicked on
if a point is clicked on, the data for the highlight trace is overwritten and the plot is redrawn
Notes
Please make sure that you are using the latest version of Plotly, otherwise the click event might not work or is buggy
In your original code the trace is drawn multiple times (remove showlegend to see it), probably because of add_markers()
Interactive JavaScript example
Plotly.d3.csv('https://raw.githubusercontent.com/plotly/datasets/master/3d-scatter.csv', function(err, rows) {
function unpack(rows, key) {
return rows.map(function(row) {
return row[key];
});
}
var trace1 = {
x: unpack(rows, 'x1').slice(0, 30),
y: unpack(rows, 'y1').slice(0, 30),
z: unpack(rows, 'z1').slice(0, 30),
mode: 'markers',
marker: {
size: 12,
line: {
color: 'rgba(217, 217, 217, 0.14)',
width: 0.5
},
opacity: 0.8
},
type: 'scatter3d'
};
var trace3 = {
x: [0],
y: [0],
z: [0],
name: 'highlight',
mode: 'markers',
type: 'scatter3d',
marker: {
size: 24,
opacity: 0.5
}
};
var data = [trace1, trace3];
var layout = {
margin: {
l: 0,
r: 0,
b: 0,
t: 0
}
};
myDiv = document.getElementById('myDiv');
Plotly.newPlot(myDiv, data);
myDiv.on('plotly_click', function(data) {
var highlight_trace = myDiv.data.length - 1;
//the coordinates of the point which was clicked on
//is found in data
var newPoint = {
x: data.points[0].x,
y: data.points[0].y,
z: data.points[0].z
};
//update the plot data and redraw it
if (myDiv.data[highlight_trace].x[0] != newPoint.x ||
myDiv.data[highlight_trace].y[0] != newPoint.y ||
myDiv.data[highlight_trace].z[0] != newPoint.z) {
myDiv.data[highlight_trace].x[0] = newPoint.x;
myDiv.data[highlight_trace].y[0] = newPoint.y
myDiv.data[highlight_trace].z[0] = newPoint.z
Plotly.redraw(myDiv);
}
});
})
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id='myDiv'></div>
I am working in SVG editor 2.7 version. Here I need to change selection area for path tags in SVG using Javascript.
For example refer this image below:
Here I analysis about SVG editor, <g> tags will generated automatically and create only one selection area which is provided only rectangular shape only.
Here I need to change selection area for path section.
Below code is based on select.js :
(function() {'use strict';
if (!svgedit.select) {
svgedit.select = {};
}
var svgFactory_;
var config_;
var selectorManager_; // A Singleton
var gripRadius = svgedit.browser.isTouch() ? 5 : 4;
// Class: svgedit.select.Selector
// Private class for DOM element selection boxes
//
// Parameters:
// id - integer to internally indentify the selector
// elem - DOM element associated with this selector
svgedit.select.Selector = function(id, elem) {
// this is the selector's unique number
this.id = id;
// this holds a reference to the element for which this selector is being used
this.selectedElement = elem;
// this is a flag used internally to track whether the selector is being used or not
this.locked = true;
// this holds a reference to the <g> element that holds all visual elements of the selector
this.selectorGroup = svgFactory_.createSVGElement({
'element': 'g',
'attr': {'id': ('selectorGroup' + this.id)}
});
// this holds a reference to the path rect
this.selectorRect = this.selectorGroup.appendChild(
svgFactory_.createSVGElement({
'element': 'path',
'attr': {
'id': ('selectedBox' + this.id),
'fill': 'none',
'stroke': '#22C',
'stroke-width': '1',
'stroke-dasharray': '5,5',
// need to specify this so that the rect is not selectable
'style': 'pointer-events:none'
}
})
);
// this holds a reference to the grip coordinates for this selector
this.gripCoords = {
'nw': null,
'n' : null,
'ne': null,
'e' : null,
'se': null,
's' : null,
'sw': null,
'w' : null
};
this.reset(this.selectedElement);
};
// Function: svgedit.select.Selector.reset
// Used to reset the id and element that the selector is attached to
//
// Parameters:
// e - DOM element associated with this selector
svgedit.select.Selector.prototype.reset = function(e) {
this.locked = true;
this.selectedElement = e;
this.resize();
this.selectorGroup.setAttribute('display', 'inline');
};
// Function: svgedit.select.Selector.updateGripCursors
// Updates cursors for corner grips on rotation so arrows point the right way
//
// Parameters:
// angle - Float indicating current rotation angle in degrees
svgedit.select.Selector.prototype.updateGripCursors = function(angle) {
var dir,
dir_arr = [],
steps = Math.round(angle / 45);
if (steps < 0) {steps += 8;}
for (dir in selectorManager_.selectorGrips) {
dir_arr.push(dir);
}
while (steps > 0) {
dir_arr.push(dir_arr.shift());
steps--;
}
var i = 0;
for (dir in selectorManager_.selectorGrips) {
selectorManager_.selectorGrips[dir].setAttribute('style', ('cursor:' + dir_arr[i] + '-resize'));
i++;
}
};
// Function: svgedit.select.Selector.showGrips
// Show the resize grips of this selector
//
// Parameters:
// show - boolean indicating whether grips should be shown or not
svgedit.select.Selector.prototype.showGrips = function(show) {
// TODO: use suspendRedraw() here
var bShow = show ? 'inline' : 'none';
selectorManager_.selectorGripsGroup.setAttribute('display', bShow);
var elem = this.selectedElement;
this.hasGrips = show;
if (elem && show) {
this.selectorGroup.appendChild(selectorManager_.selectorGripsGroup);
this.updateGripCursors(svgedit.utilities.getRotationAngle(elem));
}
};
// Function: svgedit.select.Selector.resize
// Updates the selector to match the element's size
svgedit.select.Selector.prototype.resize = function() {
console.log(this.selectorGroup);
var selectedBox = this.selectorRect,
selectorRubberBand = this.getRubberBandBox,
mgr = selectorManager_,
selectedGrips = mgr.selectorGrips,
selected = this.selectedElement,
sw = selected.getAttribute('stroke-width'),
current_zoom = svgFactory_.currentZoom();
$('#current_zoom').val(current_zoom);
console.log(mgr);
var offset = 1/current_zoom;
if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) {
offset += (sw/2);
}
var tagName = selected.tagName;
if (tagName === 'text') {
offset += 2/current_zoom;
}
// loop and transform our bounding box until we reach our first rotation
var tlist = svgedit.transformlist.getTransformList(selected);
var m = svgedit.math.transformListToTransform(tlist).matrix;
// This should probably be handled somewhere else, but for now
// it keeps the selection box correctly positioned when zoomed
m.e *= current_zoom;
m.f *= current_zoom;
var bbox = svgedit.utilities.getBBox(selected);
if (tagName === 'g' && !$.data(selected, 'gsvg')) {
// The bbox for a group does not include stroke vals, so we
// get the bbox based on its children.
var stroked_bbox = svgFactory_.getStrokedBBox(selected.childNodes);
if (stroked_bbox) {
bbox = stroked_bbox;
}
}
// apply the transforms
var l = bbox.x, t = bbox.y, w = bbox.width, h = bbox.height;
bbox = {x:l, y:t, width:w, height:h};
var x_varadd=70;
var y_varadd=40;
var cen_x=l;
var cen_y=t;
var dummyvarrr=0;
var gethide_curtselid=$("#hide_curtselid").val();
var gethide_curtselwidth=$("#hide_curtdrawx_width").val(w);
var gethide_curtselheight=$("#hide_curtdrawy_height").val(h);
$("#hide_curtdrawx_id").val(l);
$("#hide_curtdrawy_id").val(t);
var gethide_curtselid12=$("#hide_curtdrawx_id").val();
var gethide_curtselid13=$("#hide_curtdrawy_id").val();
offset *= current_zoom;
var nbox = svgedit.math.transformBox(l*current_zoom, t*current_zoom, w*current_zoom, h*current_zoom, m),
aabox = nbox.aabox,
nbax = aabox.x - offset,
nbay = aabox.y - offset,
nbaw = aabox.width + (offset * 2),
nbah = aabox.height + (offset * 2);
var gethide_curtselwidth=$("#hide_curtdrawx_width").val(nbaw);
var gethide_curtselheight=$("#hide_curtdrawy_height").val(nbah);
$("#hide_curtdrawx_id").val(nbax);
$("#hide_curtdrawy_id").val(nbay);
// now if the shape is rotated, un-rotate it
var cx = nbax + nbaw/2,
cy = nbay + nbah/2;
var angle = svgedit.utilities.getRotationAngle(selected);
if (angle) {
var rot = svgFactory_.svgRoot().createSVGTransform();
rot.setRotate(-angle, cx, cy);
var rotm = rot.matrix;
nbox.tl = svgedit.math.transformPoint(nbox.tl.x, nbox.tl.y, rotm);
nbox.tr = svgedit.math.transformPoint(nbox.tr.x, nbox.tr.y, rotm);
nbox.bl = svgedit.math.transformPoint(nbox.bl.x, nbox.bl.y, rotm);
nbox.br = svgedit.math.transformPoint(nbox.br.x, nbox.br.y, rotm);
// calculate the axis-aligned bbox
var tl = nbox.tl;
var minx = tl.x,
miny = tl.y,
maxx = tl.x,
maxy = tl.y;
var min = Math.min, max = Math.max;
minx = min(minx, min(nbox.tr.x, min(nbox.bl.x, nbox.br.x) ) ) - offset;
miny = min(miny, min(nbox.tr.y, min(nbox.bl.y, nbox.br.y) ) ) - offset;
maxx = max(maxx, max(nbox.tr.x, max(nbox.bl.x, nbox.br.x) ) ) + offset;
maxy = max(maxy, max(nbox.tr.y, max(nbox.bl.y, nbox.br.y) ) ) + offset;
nbax = minx;
nbay = miny;
nbaw = (maxx-minx);
nbah = (maxy-miny);
}
var sr_handle = svgFactory_.svgRoot().suspendRedraw(100);
var dstr = 'M' + nbax + ',' + nbay
+ ' L' + (nbax+nbaw) + ',' + nbay
+ ' ' + (nbax+nbaw) + ',' + (nbay+nbah)
+ ' ' + nbax + ',' + (nbay+nbah) + 'z';
// alert(dstr);
selectedBox.setAttribute('d', dstr);
var xform = angle ? 'rotate(' + [angle, cx, cy].join(',') + ')' : '';
this.selectorGroup.setAttribute('transform', xform);
// TODO(codedread): Is this if needed?
// if (selected === selectedElements[0]) {
this.gripCoords = {
'nw': [nbax, nbay],
'ne': [nbax+nbaw, nbay],
'sw': [nbax, nbay+nbah],
'se': [nbax+nbaw, nbay+nbah],
'n': [nbax + (nbaw)/2, nbay],
'w': [nbax, nbay + (nbah)/2],
'e': [nbax + nbaw, nbay + (nbah)/2],
's': [nbax + (nbaw)/2, nbay + nbah]
};
var width_rect = nbaw-offset;
var height_rect = nbah-offset;
var conversation =$('#measurement_det').val();
// alert(conversation);
if(conversation =='Meter') {
var width_gets = (parseFloat(width_rect)/100).toFixed(2)+'m';
var height_gets = (parseFloat(height_rect)/100).toFixed(2)+'m';
}
if(conversation =='Feet') {
var width_gets = (parseFloat(width_rect)/100)*3.2808399;
var feet_w = Math.floor(width_gets);
var inches_w = Math.round((width_gets - feet_w) * 12);
var width_gets = feet_w + "'" + inches_w + '"';
var width_gets = width_gets+'ft';
var height_gets = (parseFloat(height_rect)/100)*3.2808399;
var feet_h = Math.floor(height_gets);
var inches_h = Math.round((height_gets - feet_h) * 12);
var height_gets = feet_h + "'" + inches_h + '"';
var height_gets = height_gets+'ft';
}
if(selected.tagName=='rect')
{
var rect_text_id=selected.parentNode.id;
var rect_text_id1=rect_text_id.split('_');
}
if(selected.tagName=='g')
{
var sslice = selected.childNodes;
if(sslice[0].tagName=='rect')
{
var rect_text_id=sslice[0].parentNode.id;
var rect_text_id1=rect_text_id.split('_');
}
}
var dir;
for (dir in this.gripCoords) {
var coords = this.gripCoords[dir];
if((dir =='n') || (dir =='e') || (dir =='s') || (dir =='w')) {
/* selectedGrips[dir].setAttribute('cx', coords[0]);
selectedGrips[dir].setAttribute('cy', coords[1]); */
/* $('#selectorGrip_resize_n').html('');
$('#selectorGrip_resize_s').html(''); */
if(selected.childNodes[0] && selected.childNodes[0].tagName=='rect')
{
$('#meter_range_rect'+rect_text_id1[3]+'_n').text(width_gets);
$('#meter_range_rect'+rect_text_id1[3]+'_n').attr({'font-weight':''});
$('#meter_range_rect'+rect_text_id1[3]+'_s').text(width_gets);
$('#meter_range_rect'+rect_text_id1[3]+'_s').attr({'font-weight':''});
}
if(dir =='w') {
selectedGrips[dir].setAttribute('transform', 'rotate(-90,'+coords[0]+','+coords[1]+')');
// $('#selectorGrip_resize_w').html('');
if(selected.childNodes[0] && selected.childNodes[0].tagName=='rect')
{
$('#meter_range_rect'+rect_text_id1[3]+'_w').text(height_gets);
$('#meter_range_rect'+rect_text_id1[3]+'_w').attr({'font-weight':''});
}
}
if(dir =='e') {
selectedGrips[dir].setAttribute('transform', 'rotate(-90,'+coords[0]+','+coords[1]+')');
// $('#selectorGrip_resize_e').html('');
if(selected.childNodes[0] && selected.childNodes[0].tagName=='rect')
{
$('#meter_range_rect'+rect_text_id1[3]+'_e').text(height_gets);
$('#meter_range_rect'+rect_text_id1[3]+'_e').attr({'font-weight':''});
}
}
selectedGrips[dir].setAttribute('cx', coords[0]);
selectedGrips[dir].setAttribute('cy', coords[1]);
}
else {
selectedGrips[dir].setAttribute('cx', coords[0]);
selectedGrips[dir].setAttribute('cy', coords[1]);
}
}
// we want to go 20 pixels in the negative transformed y direction, ignoring scale
mgr.rotateGripConnector.setAttribute('x1', nbax + (nbaw)/2);
mgr.rotateGripConnector.setAttribute('y1', nbay);
mgr.rotateGripConnector.setAttribute('x2', nbax + (nbaw)/2);
mgr.rotateGripConnector.setAttribute('y2', nbay - (gripRadius*5));
mgr.rotateGrip.setAttribute('cx', nbax + (nbaw)/2);
mgr.rotateGrip.setAttribute('cy', nbay - (gripRadius*5));
// }
svgFactory_.svgRoot().unsuspendRedraw(sr_handle);
};
// Class: svgedit.select.SelectorManager
svgedit.select.SelectorManager = function() {
// this will hold the <g> element that contains all selector rects/grips
this.selectorParentGroup = null;
// this is a special rect that is used for multi-select
this.rubberBandBox = null;
// this will hold objects of type svgedit.select.Selector (see above)
this.selectors = [];
// this holds a map of SVG elements to their Selector object
this.selectorMap = {};
// this holds a reference to the grip elements
this.selectorGrips = {
'nw': null,
'n' : null,
'ne': null,
'e' : null,
'se': null,
's' : null,
'sw': null,
'w' : null
};
this.selectorGripsGroup = null;
this.rotateGripConnector = null;
this.rotateGrip = null;
this.initGroup();
};
// Function: svgedit.select.SelectorManager.initGroup
// Resets the parent selector group element
svgedit.select.SelectorManager.prototype.initGroup = function() {
// remove old selector parent group if it existed
if (this.selectorParentGroup && this.selectorParentGroup.parentNode) {
this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup);
}
// create parent selector group and add it to svgroot
this.selectorParentGroup = svgFactory_.createSVGElement({
'element': 'g',
'attr': {'id': 'selectorParentGroup'}
});
this.selectorGripsGroup = svgFactory_.createSVGElement({
'element': 'g',
'attr': {'display': 'none'}
});
this.selectorParentGroup.appendChild(this.selectorGripsGroup);
svgFactory_.svgRoot().appendChild(this.selectorParentGroup);
this.selectorMap = {};
this.selectors = [];
this.rubberBandBox = null;
// add the corner grips
var dir;
for (dir in this.selectorGrips) {
var grip = svgFactory_.createSVGElement({
'element': 'circle',
'attr': {
'id': ('selectorGrip_resize_' + dir),
'fill': '#04739E',
'r': gripRadius,
'style': ('cursor:' + dir + '-resize'),
// This expands the mouse-able area of the grips making them
// easier to grab with the mouse.
// This works in Opera and WebKit, but does not work in Firefox
// see https://bugzilla.mozilla.org/show_bug.cgi?id=500174
'stroke-width': 2,
'pointer-events': 'all'
}
});
/* if((dir =='n') || (dir =='e') || (dir =='s') || (dir =='w')) {
var grip = svgFactory_.createSVGElement({
'element': 'text',
'attr': {
'id': ('selectorGrip_resize_' + dir),
'fill': '#3F7F00',
// 'r': gripRadius,
'style': ('cursor:' + dir + '-resize'),
// This expands the mouse-able area of the grips making them
// easier to grab with the mouse.
// This works in Opera and WebKit, but does not work in Firefox
// see https://bugzilla.mozilla.org/show_bug.cgi?id=500174
'stroke-width': 2,
'pointer-events': 'all'
}
});
grip.textContent = '';
}else {
var grip = svgFactory_.createSVGElement({
'element': 'circle',
'attr': {
'id': ('selectorGrip_resize_' + dir),
'fill': '#04739E',
'r': gripRadius,
'style': ('cursor:' + dir + '-resize'),
// This expands the mouse-able area of the grips making them
// easier to grab with the mouse.
// This works in Opera and WebKit, but does not work in Firefox
// see https://bugzilla.mozilla.org/show_bug.cgi?id=500174
'stroke-width': 2,
'pointer-events': 'all'
}
});
}
*/
$.data(grip, 'dir', dir);
$.data(grip, 'type', 'resize');
this.selectorGrips[dir] = this.selectorGripsGroup.appendChild(grip);
}
// add rotator elems
this.rotateGripConnector = this.selectorGripsGroup.appendChild(
svgFactory_.createSVGElement({
'element': 'line',
'attr': {
'id': ('selectorGrip_rotateconnector'),
'stroke': '#22C',
'stroke-width': '0'
}
})
);
this.rotateGrip = this.selectorGripsGroup.appendChild(
svgFactory_.createSVGElement({
'element': 'circle',
'attr': {
'id': 'selectorGrip_rotate',
'fill': 'url(#rotate)',
'r': '15',
'stroke': '#22C',
'stroke-width': 2,
'style': "cursor:url(" + config_.imgPath + "rotate.png) 12 12, auto;"
}
})
);
$.data(this.rotateGrip, 'type', 'rotate');
if ($('#canvasBackground').length) {return;}
var dims = config_.dimensions;
var canvasbg = svgFactory_.createSVGElement({
'element': 'svg',
'attr': {
'id': 'canvasBackground',
'width': dims[0],
'height': dims[1],
'x': 0,
'y': 0,
'overflow': (svgedit.browser.isWebkit() ? 'none' : 'visible'), // Chrome 7 has a problem with this when zooming out
'style': 'pointer-events:none'
}
});
var rect = svgFactory_.createSVGElement({
'element': 'rect',
'attr': {
'width': '100%',
'height': '100%',
'x': 0,
'y': 0,
'stroke-width': 1,
'stroke': '#000',
'fill': '#FFF',
'style': 'pointer-events:none'
}
});
// Both Firefox and WebKit are too slow with this filter region (especially at higher
// zoom levels) and Opera has at least one bug
// if (!svgedit.browser.isOpera()) rect.setAttribute('filter', 'url(#canvashadow)');
canvasbg.appendChild(rect);
svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent());
};
// Function: svgedit.select.SelectorManager.requestSelector
// Returns the selector based on the given element
//
// Parameters:
// elem - DOM element to get the selector for
svgedit.select.SelectorManager.prototype.requestSelector = function(elem) {
if (elem == null) {return null;}
var i,
N = this.selectors.length;
// If we've already acquired one for this element, return it.
if (typeof(this.selectorMap[elem.id]) == 'object') {
this.selectorMap[elem.id].locked = true;
$("#hide_curtselid").val(elem.id);
return this.selectorMap[elem.id];
}
for (i = 0; i < N; ++i) {
if (this.selectors[i] && !this.selectors[i].locked) {
this.selectors[i].locked = true;
this.selectors[i].reset(elem);
this.selectorMap[elem.id] = this.selectors[i];
return this.selectors[i];
}
}
// if we reached here, no available selectors were found, we create one
this.selectors[N] = new svgedit.select.Selector(N, elem);
this.selectorParentGroup.appendChild(this.selectors[N].selectorGroup);
this.selectorMap[elem.id] = this.selectors[N];
return this.selectors[N];
};
// Function: svgedit.select.SelectorManager.requestSelectors
// Returns the selector based on the given Rect and line and Path
//
// Parameters:
// elem - DOM element to get the selector for
svgedit.select.SelectorManager.prototype.requestSelectors = function(elem) {
if (elem == null) {return null;}
var i,
N = this.selectors.length;
// console.log(elem);
// If we've already acquired one for this element, return it.
if (typeof(this.selectorMap[elem.id]) == 'object') {
this.selectorMap[elem.id].locked = true;
$("#hide_curtselid").val(elem.id);
return this.selectorMap[elem.id];
}
for (i = 0; i < N; ++i) {
if (this.selectors[i] && !this.selectors[i].locked) {
this.selectors[i].locked = true;
this.selectors[i].reset(elem);
this.selectorMap[elem.id] = this.selectors[i];
return this.selectors[i];
}
}
// if we reached here, no available selectors were found, we create one
this.selectors[N] = new svgedit.select.Selector(N, elem);
this.selectorParentGroup.appendChild(this.selectors[N].selectorGroup);
this.selectorMap[elem.id] = this.selectors[N];
return this.selectors[N];
};
// Function: svgedit.select.SelectorManager.releaseSelector
// Removes the selector of the given element (hides selection box)
//
// Parameters:
// elem - DOM element to remove the selector for
svgedit.select.SelectorManager.prototype.releaseSelector = function(elem) {
if (elem == null) {return;}
var i,
N = this.selectors.length,
sel = this.selectorMap[elem.id];
for (i = 0; i < N; ++i) {
if (this.selectors[i] && this.selectors[i] == sel) {
if (sel.locked == false) {
// TODO(codedread): Ensure this exists in this module.
console.log('WARNING! selector was released but was already unlocked');
}
delete this.selectorMap[elem.id];
sel.locked = false;
sel.selectedElement = null;
sel.showGrips(false);
// remove from DOM and store reference in JS but only if it exists in the DOM
try {
sel.selectorGroup.setAttribute('display', 'none');
} catch(e) { }
break;
}
}
};
// Function: svgedit.select.SelectorManager.getRubberBandBox
// Returns the rubberBandBox DOM element. This is the rectangle drawn by the user for selecting/zooming
svgedit.select.SelectorManager.prototype.getRubberBandBox = function() {
if (!this.rubberBandBox) {
this.rubberBandBox = this.selectorParentGroup.appendChild(
svgFactory_.createSVGElement({
'element': 'path',
'attr': {
'id': 'selectorRubberBand',
'fill': '#22C',
'fill-opacity': 0.15,
'stroke': '#22C',
'stroke-width': 10.5,
'display': 'block',
'style': 'pointer-events:none'
}
})
);
}
return this.rubberBandBox;
};
/**
* Interface: svgedit.select.SVGFactory
* An object that creates SVG elements for the canvas.
*
* interface svgedit.select.SVGFactory {
* SVGElement createSVGElement(jsonMap);
* SVGSVGElement svgRoot();
* SVGSVGElement svgContent();
*
* Number currentZoom();
* Object getStrokedBBox(Element[]); // TODO(codedread): Remove when getStrokedBBox() has been put into svgutils.js
* }
*/
/**
* Function: svgedit.select.init()
* Initializes this module.
*
* Parameters:
* config - an object containing configurable parameters (imgPath)
* svgFactory - an object implementing the SVGFactory interface (see above).
*/
svgedit.select.init = function(config, svgFactory) {
config_ = config;
svgFactory_ = svgFactory;
selectorManager_ = new svgedit.select.SelectorManager();
};
/**
* Function: svgedit.select.getSelectorManager
*
* Returns:
* The SelectorManager instance.
*/
svgedit.select.getSelectorManager = function() {
return selectorManager_;
};
}());
Dynamic create <g> tags based
<g id="selectorParentGroup" >
<rect id="selectorRubberBand" fill="#22C" fill-opacity="0.15" stroke="#22C" stroke-width="10.5" display="none" style="pointer-events:none" x="2034" y="909.800048828125" width="0" height="0"/>
<path id="selectedBox0" fill="none" stroke="#22C" stroke-dasharray="5,5" style="pointer-events:none" d="M2057,948.716552734375 L2280.5,948.716552734375 2280.5,1092 2057,1092z"/>
</g>
Just check both attached images, we are on the first stage (image) we to make it us the second stage - Selection area should be in over boundary as in secondary image (should be as image right side). Kindly assist me.
All suggestion will be highly appreciated.
I'm trying to change the default orientation in a space tree but can't figure out where to add:
st.switchPosition("top", "animate", {
onComplete: function() {
alert('completed!');
}
});
So that the tree will start from the top instead of the default of right.
In the examples i've seen, the switchPosition is only used with an event handler, which i do not intend to have.
So in the example (taken from the infovis site:Infovis - spacetree ), where should i add the code (or any code) in order to change the default orientation?
var labelType, useGradients, nativeTextSupport, animate;
(function() {
var ua = navigator.userAgent,
iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
typeOfCanvas = typeof HTMLCanvasElement,
nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
textSupport = nativeCanvasSupport
&& (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
//I'm setting this based on the fact that ExCanvas provides text support for IE
//and that as of today iPhone/iPad current text support is lame
labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
nativeTextSupport = labelType == 'Native';
useGradients = nativeCanvasSupport;
animate = !(iStuff || !nativeCanvasSupport);
})();
var Log = {
elem: false,
write: function(text){
if (!this.elem)
this.elem = document.getElementById('log');
this.elem.innerHTML = text;
this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
}
};
function init(){
//init data
var json = {....removed due to space here in the group....}
//end
//A client-side tree generator
var getTree = (function() {
var i = 0;
return function(nodeId, level) {
var subtree = eval('(' + json.replace(/id:\"([a-zA-Z0-9]+)\"/g,
function(all, match) {
return "id:\"" + match + "_" + i + "\""
}) + ')');
$jit.json.prune(subtree, level); i++;
return {
'id': nodeId,
'children': subtree.children
};
};
})();
//Implement a node rendering function called 'nodeline' that plots a straight line
//when contracting or expanding a subtree.
$jit.ST.Plot.NodeTypes.implement({
'nodeline': {
'render': function(node, canvas, animating) {
if(animating === 'expand' || animating === 'contract') {
var pos = node.pos.getc(true), nconfig = this.node, data = node.data;
var width = nconfig.width, height = nconfig.height;
var algnPos = this.getAlignedPos(pos, width, height);
var ctx = canvas.getCtx(), ort = this.config.orientation;
ctx.beginPath();
if(ort == 'left' || ort == 'right') {
ctx.moveTo(algnPos.x, algnPos.y + height / 2);
ctx.lineTo(algnPos.x + width, algnPos.y + height / 2);
} else {
ctx.moveTo(algnPos.x + width / 2, algnPos.y);
ctx.lineTo(algnPos.x + width / 2, algnPos.y + height);
}
ctx.stroke();
}
}
}
});
//init Spacetree
//Create a new ST instance
var st = new $jit.ST({
'injectInto': 'infovis',
//set duration for the animation
duration: 800,
//set animation transition type
transition: $jit.Trans.Quart.easeInOut,
//set distance between node and its children
levelDistance: 50,
//set max levels to show. Useful when used with
//the request method for requesting trees of specific depth
levelsToShow: 2,
//set node and edge styles
//set overridable=true for styling individual
//nodes or edges
Node: {
height: 20,
width: 40,
//use a custom
//node rendering function
type: 'nodeline',
color:'#23A4FF',
lineWidth: 2,
align:"center",
overridable: true
},
Edge: {
type: 'bezier',
lineWidth: 2,
color:'#23A4FF',
overridable: true
},
//Add a request method for requesting on-demand json trees.
//This method gets called when a node
//is clicked and its subtree has a smaller depth
//than the one specified by the levelsToShow parameter.
//In that case a subtree is requested and is added to the dataset.
//This method is asynchronous, so you can make an Ajax request for that
//subtree and then handle it to the onComplete callback.
//Here we just use a client-side tree generator (the getTree function).
request: function(nodeId, level, onComplete) {
var ans = getTree(nodeId, level);
onComplete.onComplete(nodeId, ans);
},
onBeforeCompute: function(node){
Log.write("loading " + node.name);
},
onAfterCompute: function(){
Log.write("done");
},
//This method is called on DOM label creation.
//Use this method to add event handlers and styles to
//your node.
onCreateLabel: function(label, node){
label.id = node.id;
label.innerHTML = node.name;
label.onclick = function(){
st.onClick(node.id);
};
//set label styles
var style = label.style;
style.width = 40 + 'px';
style.height = 17 + 'px';
style.cursor = 'pointer';
style.color = '#fff';
//style.backgroundColor = '#1a1a1a';
style.fontSize = '0.8em';
style.textAlign= 'center';
style.textDecoration = 'underline';
style.paddingTop = '3px';
},
//This method is called right before plotting
//a node. It's useful for changing an individual node
//style properties before plotting it.
//The data properties prefixed with a dollar
//sign will override the global node style properties.
onBeforePlotNode: function(node){
//add some color to the nodes in the path between the
//root node and the selected node.
if (node.selected) {
node.data.$color = "#ff7";
}
else {
delete node.data.$color;
}
},
//This method is called right before plotting
//an edge. It's useful for changing an individual edge
//style properties before plotting it.
//Edge data proprties prefixed with a dollar sign will
//override the Edge global style properties.
onBeforePlotLine: function(adj){
if (adj.nodeFrom.selected && adj.nodeTo.selected) {
adj.data.$color = "#eed";
adj.data.$lineWidth = 3;
}
else {
delete adj.data.$color;
delete adj.data.$lineWidth;
}
}
});
//load json data
st.loadJSON(eval( '(' + json + ')' ));
//compute node positions and layout
st.compute();
//emulate a click on the root node.
st.onClick(st.root);
//end
//Add event handlers to switch spacetree orientation. - Which i do not want...
// function get(id) {
// return document.getElementById(id);
// };
// var top = get('r-top'),
// left = get('r-left'),
// bottom = get('r-bottom'),
// right = get('r-right');
// function changeHandler() {
// if(this.checked) {
// top.disabled = bottom.disabled = right.disabled = left.disabled = true;
// st.switchPosition(this.value, "animate", {
// onComplete: function(){
// top.disabled = bottom.disabled = right.disabled = left.disabled = false;
// }
// });
// }
// };
// top.onchange = left.onchange = bottom.onchange = right.onchange = changeHandler;
//end
}
You can drop in orientation:'top', shortly into the new $jit.ST function, ie:
var st = new $jit.ST({
//id of viz container element
injectInto: 'infovis',
//SET THE TREE TO VERTICAL
orientation:"top",
//set duration for the animation
duration: 800,
Source: https://groups.google.com/forum/#!searchin/javascript-information-visualization-toolkit/top/javascript-information-visualization-toolkit/MhXSXJUmaIk/V5JNwSe359gJ
I am loading a shapefile from a server and than drawing it n OpenLayers. The shapefile contains over 400,000 multipolygons with varying opacity. I need to set the opacity and fill color yet openlayers seems to be ignoring it and just drawing orange squares instead. I console.log() before I change the attributes and after and it shows what I assigned it. Can anyone tell me why it is doing that?
var green = {
fill: true,
fillColor: "#006633",
fillOpacity: 1
};
var features = wkt.read(element);
if (featureNumber == 0){
document.getElementById('result').innerHTML=element;
}
features = element.toString();
var bounds;
var b = features.indexOf('MULTIPOLYGON', 0);
var c = features.indexOf('MULTIPOLYGON', 40);
if (c == -1) {
c = element.indexOf(':',b+1);
}
leftovers = features.substring(c,100000000000000000);
features = features.substring(b,c);
features = wkt.read(features);
if(features) {
if(features.constructor != Array) {
features = [features];
}
for(var i=0; i<features.length; ++i) {
if (!bounds) {
bounds = features[i].geometry.getBounds();
} else {
bounds.extend(features[i].geometry.getBounds());
}
}
pointLayer.addFeatures(features);
console.log(pointLayer.features[featureNumber].attributes );
pointLayer.features[featureNumber].attributes = green;
console.log(pointLayer.features[featureNumber].attributes );
featureNumber++
map.zoomToExtent(bounds);
var plural = (features.length > 1) ? 's' : '';
console.log('Feature' + plural + ' added');
console.log('feature number: '+featureNumber)
if (leftovers.indexOf('MULTIPOLYGON',0) != -1) {
parseWKT(leftovers,shapefile);
}
} else {
final(leftovers, shapefile);
}
}
well the style belongs in the .style property not the .attributes of the feature. You'll also need to call redraw() if it's already on the map.
pointLayer.features[featureNumber].style = green;
pointLayer.redraw();
If you want to start out with the default style and just change a few things, you can do something like this:
var green = OpenLayers.Util.applyDefaults(green, OpenLayers.Feature.Vector.style['default']);
green.fill = true;
green.fillColor = "#006633";
green.fillOpacity = 1;
pointLayer.features[featureNumber].style = green;
pointLayer.redraw();
Is it possible to set the background color of one Row in a Table? I need to highlight a row when a condition applies. Something to the effect of < tr font="...">...< /tr> where I can specify the "font" attributes. (I need the whole row to be highlighted).
you have to subclass the qooxdoo default row renderer to make that happen.
Take a look at the following code which you can test in the qooxdoo playground. It shows you how to do it.
function createRandomRows(rowCount) {
var rowData = [];
var now = new Date().getTime();
var nextId = 0;
for (var row = 0; row < rowCount; row++) {
rowData.push([ nextId++, Math.random() * 10000]);
}
return rowData;
}
// window
var win = new qx.ui.window.Window("Table").set({
layout : new qx.ui.layout.Grow(),
contentPadding: 0
});
this.getRoot().add(win);
win.open();
// table model
var tableModel = new qx.ui.table.model.Simple();
tableModel.setColumns([ "ID", "A number" ]);
tableModel.setData(createRandomRows(10000));
// table
var table = new qx.ui.table.Table(tableModel).set({decorator: null})
/**
* New row renderer!
*/
qx.Class.define("condRow", {
extend : qx.ui.table.rowrenderer.Default,
members : {
// overridden
updateDataRowElement : function(rowInfo, rowElem)
{
this.base(arguments, rowInfo, rowElem);
var style = rowElem.style;
if (!(rowInfo.focusedRow && this.getHighlightFocusRow()) && !rowInfo.selected) {
style.backgroundColor = (rowInfo.rowData[1] > 5000) ? this.__colors.bgcolEven : this.__colors.bgcolOdd;
}
},
// overridden
createRowStyle : function(rowInfo)
{
var rowStyle = [];
rowStyle.push(";");
rowStyle.push(this.__fontStyleString);
rowStyle.push("background-color:");
if (rowInfo.focusedRow && this.getHighlightFocusRow())
{
rowStyle.push(rowInfo.selected ? this.__colors.bgcolFocusedSelected : this.__colors.bgcolFocused);
}
else
{
if (rowInfo.selected)
{
rowStyle.push(this.__colors.bgcolSelected);
}
else
{
// here is the second magic
rowStyle.push((rowInfo.rowData[1] > 5000) ? this.__colors.bgcolEven : this.__colors.bgcolOdd);
}
}
rowStyle.push(';color:');
rowStyle.push(rowInfo.selected ? this.__colors.colSelected : this.__colors.colNormal);
rowStyle.push(';border-bottom: 1px solid ', this.__colors.horLine);
return rowStyle.join("");
},
}
});
table.setDataRowRenderer(new condRow(table));
win.add(table);
At the bottom of the code you see the new row renderer which marks all rows having a bigger number than 5000 in the second column.
​Regards,
Martin
Here's a version of Martin Wittemann's answer that works in the playground (1.6 tested):
/** This renderer makes rows matching our conditions appear as different colours */
qx.Class.define("CustomRowRenderer", {
extend : qx.ui.table.rowrenderer.Default,
members : {
/** Overridden to handle our custom logic for row colouring */
updateDataRowElement : function(rowInfo, rowElem) {
// Call super first
this.base(arguments, rowInfo, rowElem);
// Get the current style
var style = rowElem.style;
// Don't overwrite the style on the focused / selected row
if (!(rowInfo.focusedRow && this.getHighlightFocusRow()) && !rowInfo.selected) {
// Apply our rule for row colouring
style.backgroundColor = (rowInfo.rowData[1] > 5000) ? this._colors.bgcolEven : this._colors.bgcolOdd;
}
},
/** Overridden to handle our custom logic for row colouring */
createRowStyle : function(rowInfo) {
// Create some style
var rowStyle = [];
rowStyle.push(";");
rowStyle.push(this.__fontStyleString);
rowStyle.push("background-color:");
// Are we focused?
if (rowInfo.focusedRow && this.getHighlightFocusRow()) {
// Handle the focused / selected row as normal
rowStyle.push(rowInfo.selected ? this._colors.bgcolFocusedSelected : this._colors.bgcolFocused);
} else {
// Aew we selected?
if (rowInfo.selected) {
// Handle the selected row as normal
rowStyle.push(this._colors.bgcolSelected);
} else {
// Apply our rule for row colouring
rowStyle.push((rowInfo.rowData[1] > 5000) ? this._colors.bgcolEven : this._colors.bgcolOdd);
}
}
// Finish off the style string
rowStyle.push(';color:');
rowStyle.push(rowInfo.selected ? this._colors.colSelected : this._colors.colNormal);
rowStyle.push(';border-bottom: 1px solid ', this._colors.horLine);
return rowStyle.join("");
}
}
});
// Demo table
var tableModel = new qx.ui.table.model.Simple();
tableModel.setColumns([ "ID", "Number" ]);
tableModel.setData([
[1, 5000],
[1, 6000],
[1, 6000],
[1, 6000],
[1, 6000],
[1, 4000],
[1, 4000],
[1, 4000],
[1, 6000]
]);
var table = new qx.ui.table.Table(tableModel);
// Apply our renderer
table.setDataRowRenderer(new CustomRowRenderer(table));
// Add table
this.getRoot().add(table, { left : 10, top : 10 });