I have some d3 code with drag and drop support. I have an imported SVG with a limited polygon area inside. I need to add RECS to this area and limit drag and drop support inside this area boundaries. Does anyone know how to do this? The main problem is I cant do a function to calculate this area because it is variable.
Thank a lot for your help!
Note: I created a jsfiddle link.
SVG File XML (image data has been eliminated)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="3386"
height="1498"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="SAL_default_at.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="1220.1429"
inkscape:cy="749"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1600"
inkscape:window-height="1138"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
borderlayer="false"
showborder="false"
inkscape:showpageshadow="false" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(1343,216.63782)">
<image
y="-216.63782"
x="-1343"
id="image2993"
xlink:href="data has been elminated"
height="1498"
width="3386" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="capaAreaTrabajo"
transform="translate(1343,216.63782)">
<path
style="opacity:0.05;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -1285.7143,58.076468 677.14287,2.857143 -5.71428,551.428569 539.999996,-2.85714 -2.857143,368.57143 -1128.571443,-2.85714 z"
id="d3AreaTrabajo"
inkscape:connector-curvature="0"
inkscape:label="d3AreaTrabajo" />
</g>
</svg>
D3 call function
function d3plantExplorerGenerarMapa(movilabDataset, w, h, anchoSalaCm, altoSalaCm, dwh, urlImagenFondoSvg, reescalado) {
var urlFondo2 = urlImagenFondoSvg.replace(".png", "_at.svg");
d3.xml(urlFondo2, "image/svg+xml", function(xml) {
var importedNode = document.importNode(xml.documentElement, true);
d3.select("#d3PlantExplorer").node().appendChild(importedNode);
var svgTmp = d3.select("#svg2");
d3plantExplorerGenerarMapaProcess(movilabDataset, w, h, anchoSalaCm, altoSalaCm, dwh, urlImagenFondoSvg, reescalado, svgTmp);
});
}
function d3plantExplorerGenerarMapaProcess(movilabDataset, w, h, anchoSalaCm, altoSalaCm, dwh, urlImagenFondoSvg, reescalado, rootSvgImported) {
console.log("d3plantExplorerGenerarMapa --> init");
//
// Imagen de fondo para usar. Representa la planta.
//
var urlFondo = urlImagenFondoSvg;
//
// Datos para pintar en formato JSON
//
// NOTA: Si los datos NO viajan no sobreescribimos.
if(movilabDataset != null) {
svgJsonData = JSON.parse(movilabDataset);
jsonMovilabDataset = svgJsonData;
}
//
// Definimos la escala
//
// - Dominio -> Datos REALES que viajarán en el dataset.
// en nuestro caso posicion X,Y en CM en una sala. Por tanto nuestro dominio es {0, ancho/alto sala}
//
// - Rango -> Representa nuestro máximo valor en la VISUAL, es decir, en el explorador.
// En nuestro caso representa el alto y el ancho DE LA IMAGEN EN NAVEGADOR, es decir {0, ancho/alto imagens svg}
//
var widthCm = anchoSalaCm;
var higthtCm = altoSalaCm;
widthScaleCm2Px = d3.scale.linear() //this.
.domain([0, widthCm])
.range([0, w]);
heightScaleCm2Px = d3.scale.linear() //this.
.domain([0, higthtCm])
.range([0, h]);
/*
this.widthScalePx2Cm = d3.scale.linear()
.domain([0, w])
.range([0, widthCm]);
this.heightScalePx2Cm = d3.scale.linear()
.domain([0, h])
.range([0, higthtCm]);
*/
//
// Ejes
//
/*
xAxis = d3.svg.axis()
.scale(widthScaleCm2Px)
.orient("bottom")
.tickSize(-h);
yAxis = d3.svg.axis()
.scale(heightScaleCm2Px)
.orient("left")
.ticks(5)
.tickSize(-w);
*/
//
// Variable para controlar el zoom.
//
var zoomListener = d3.behavior.zoom()
.on("zoom", d3zoomHandler);
var zoomListener2 = d3.behavior.zoom()
.on("zoom", d3zoomHandler2);
//
// Variable para controlar los eventos Drag&Drop usado el motor D3
// Nota: El evento dragend se dispara con el evento onclick.
//
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", d3dragstarted)
.on("drag", d3dragged)
.on("dragend", d3dragended);
//
// Comprobamos que no exista la imagen SVG ya creada en el cliente
// Si NO existe la creamos y si existe borramos todos los elementos
// creados y repintamos.
//
// NOTA: La consistencia de los datos a pintar la mantiene el codigo java del backing bean
var svgBackgrounImageId = "d3PlantExplorerBackgroundImage";
var svgBackgrounImageQueryId = "#" + svgBackgrounImageId;
var svgName = "d3PlantExplorerSvg";
var svgQueryName = "#" + svgName;
console.log("d3plantExplorerGenerarMapa [01] --> OK");
if(rootSvgImported != null) {
rootSvg = rootSvgImported;
}
if(d3.select(svgQueryName).empty()) {
/*
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.attr("id", "d3PlantExplorerSvgTooltip")
.text("Sin Datos");
svg = d3.select("#d3PlantExplorer")
.append("svg")
.attr("id", "d3PlantExplorerSvg")
.attr("width", w)
.attr("height", h)
.style("border", "1px solid black");
*/
if(rootSvgImported == null) {
rootSvg = d3.select("#d3PlantExplorer")
.append("svg")
.attr("id", svgName)
.attr("width", w)
.attr("height", h)
.style("border", "0px solid black")
.append("g");
}
if(rootSvgImported == null) {
imgs = rootSvg.selectAll("image").data([0]);
imgs.enter()
.append("svg:image")
.attr("id", svgBackgrounImageId)
.attr("xlink:href", urlFondo)
.attr("x", "0")
.attr("y", "0")
.attr("width", w)
.attr("height", h);
}
console.log("d3plantExplorerGenerarMapa [02] --> OK");
} else if(reescalado == 1) {
console.log("d3plantExplorerGenerarMapa [03] --> OK");
} else {
rootSvg = d3.select(svgQueryName);
rootSvg.selectAll("rect").data([]).exit().remove();
rootSvg.attr("width", w)
.attr("height", h);
imgs = d3.select(svgBackgrounImageQueryId);
imgs.attr("width", w)
.attr("height", h);
console.log("d3plantExplorerGenerarMapa [04] --> OK");
}
//
// Añadimos los racks
//
svg = rootSvg.append("g");
//svg = rootSvg;
svg.selectAll("rect")
.data(svgJsonData)
.enter()
.append("rect")
.on("mousedown", function(d) {
d3.event.stopPropagation();
d3.event.preventDefault();
console.log("rect [mousedown] --> OK");
d3highlightElement(d.cfgInsRack_identificador, fillColorOn, true);
})
.on("click", function(d) {
d3.event.stopPropagation();
d3.event.preventDefault();
console.log("rect [click] --> OK");
// Actualizamos el tooltip
d3.select("#d3TooltipRackSeleccionado").text(d.cfgInsRack_info);
d3.select("#d3TooltipRackNoSeleccionado").text(d.cfgInsRack_info);
d3generateMouseTooltip(d.cfgInsRack_identificador, null, 0);
// Comprobamos el click
if(d3CiSelected != d.cfgInsRack_identificador) {
// Marcamos el elemento actual como selccionado
d3highlightElement(d3CiSelected, null, false);
d3CiSelected = d.cfgInsRack_identificador;
d3highlightElement(d3CiSelected, fillColorOn, true);
// Mostramos y ocultamos el panel de información de rack
//d3ShowHideElement("d3PanelOperacionesRacks",1,0,0);
d3ShowHideElement("d3PanelOperacionesRacksRackSeleccionado",1,0,0);
d3ShowHideElement("d3PanelOperacionesRacksRackNoSeleccionado",0,0,0);
// Notificamos a Movilab el CI que estamos seleccionando.
d3plantExplorerClickHandler(2, d3.mouse(this), d);
} else {
}
})
.on("dblclick", function(d) {
d3.event.stopPropagation();
d3.event.preventDefault();
//d3plantExplorerClickHandler(2, d3.mouse(this), d);
//d3plantExplorerClickHandler(51, d3.mouse(this), d);
})
.on("contextmenu", function(d) {
d3.event.stopPropagation();
d3.event.preventDefault();
// Actualizamos el tooltip
d3.select("#d3TooltipRackSeleccionado").text(d.cfgInsRack_info);
d3.select("#d3TooltipRackNoSeleccionado").text(d.cfgInsRack_info);
//d3plantExplorerClickHandler(2, d3.mouse(this), d);
//d3plantExplorerClickHandler(51, d3.mouse(this), d);
// Mostramos el panel de informacion
//d3PanelInfoCiShowHide(0);
// Menu contextual para el plano
d3ContextMenuAttach(d.cfgInsRack_identificador, contextualMenuRectDataSet, "contextmenu");
})
.on("mouseover", function(d) {
if(!isDragging) {
d3.event.stopPropagation();
d3.event.preventDefault();
console.log("rect [mouseover] --> OK");
// Menu contextual para el plano
d3highlightElement(d.cfgInsRack_identificador, fillColorOn, true);
// Actualizamos el tooltip
d3.select("#d3TooltipRackNoSeleccionado").text(d.cfgInsRack_info);
// Tooltip
d3generateMouseTooltip(d.cfgInsRack_identificador, d.cfgInsRack_info + "<br>Estado: " + d.cfgInsRack_estado, 1);
}
// Notificamos a Movilab el CI que estamos seleccionando.
//d3plantExplorerClickHandler(2, d3.mouse(this), d);
})
.on("mouseout", function(d) {
d3.event.stopPropagation();
d3.event.preventDefault();
console.log("rect [mouseout] --> OK");
d3.select("#d3TooltipRackNoSeleccionado").text("");
d3generateMouseTooltip(d.cfgInsRack_identificador, null, 0);
if(d3CiSelected != d.cfgInsRack_identificador) {
d3highlightElement(d.cfgInsRack_identificador, d.color, false);
}
//d3PanelInfoCiShowHide(0);
})
.call(drag)
.attr("id", function(d) { return d.cfgInsRack_identificador; })
.attr("x", function(d) {
var px = widthScaleCm2Px(d.x_axisCm);
console.log("d3Info [" + d.cfgInsRack_identificador + "] --> " + "(x)=px:" + px + ", cm:" + d.x_axisCm);
d.x_axisPx = px;
return d.x_axisPx;
})
.attr("y", function(d) {
var px = heightScaleCm2Px(d.y_axisCm);
console.log("d3Info [" + d.cfgInsRack_identificador + "] --> " + "(y)=px:" + px + ", cm:" + d.y_axisCm);
d.y_axisPx = px;
return d.y_axisPx;
})
.attr("width", function(d) {
var px = widthScaleCm2Px(d.x_anchoCm);
console.log("d3Info [" + d.cfgInsRack_identificador + "] --> " + "(width)=px:" + px + ", cm:" + d.x_anchoCm);
d.x_anchoPx = px;
return d.x_anchoPx;
})
.attr("height", function(d) {
var px = heightScaleCm2Px(d.y_altoCm);
console.log("d3Info [" + d.cfgInsRack_identificador + "] --> " + "(height)=px:" + px + ", cm:" + d.y_altoCm);
d.y_altoPx = px;
return d.y_altoPx;
})
//.attr("rx", 10) // curva redondeada
//.attr("ry", 10) // curva redondeada
.attr("stroke", strokeOpacityColorOff)
.attr("fill", function(d) { return d.color; })
.attr("stroke-opacity", strokeOpacityOff) //0.1
.attr("fill-opacity", function(d){
if(d.ocupado==1) {
return 0.5;
}
return 0.5;
})
.attr("display", function(d) {
// Verificamos que tenemos que verlo, es decir que la posicion no sea 0,0
if(d.x_axisCm == 0 || d.y_axisCm == 0) {
return "none";
}
return "block";
});
console.log("d3plantExplorerGenerarMapa [07] --> OK");
// Listener para ZOOM
zoomListener(rootSvg);
console.log("d3plantExplorerGenerarMapa [08] --> OK");
// Eventos asociados al "RECT" que acabamos de crear-
// Menu contextual para el plano
d3ContextMenuAttach(svgName, contextualMenuSvgDataSet, "contextmenu");
// Mostramos y ocultamos el panel de información de rack
//d3ShowHideElement("d3PanelOperacionesRacks",0,0,0);
d3ShowHideElement("d3PanelOperacionesRacksRackSeleccionado",0,0,0);
d3ShowHideElement("d3PanelOperacionesRacksRackNoSeleccionado",1,0,0);
// Al hacer click sobre el plano borramos todos los menus
rootSvg.on("click", function(d) {
d3ContextMenuRemove(null);
})
console.log("d3plantExplorerGenerarMapa [09] --> OK");
// Marcamos el SVG como creado.
svgCreated = true; //this.
console.log("d3plantExplorerGenerarMapa --> fin");
}