How to place a object without tapping on the screen - java

I am trying to show an object without tapping on the screen using ARCore. In the basic sample of ARCore Sceneform provided by Google, you need to tap on the screen after it detects the surface.
I want to implement that, AR shows the object without tapping on the screen.
Anchor newAnchor;
for (Plane plane : mSession.getAllTrackables(Plane.class)) {
if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING
&& plane.getTrackingState() == TrackingState.TRACKING)
{
newAnchor = plane.createAnchor(plane.getCenterPose());
break;
}
}
I tried this for displaying without tapping on the screen.
if Anyone know how to do this please help me. Thanks in Advance

Although I suggest you place the object when a user taps & where s/he taps on the screen, what you're asking can be achieved like so. (this example is in Kotlin)
Before you begin placing an object, you need to create a ModelRenderable. Declare one #Nullable globally.
private var modelRenderable: ModelRenderable? = null
//Create the football renderable
ModelRenderable.builder()
//get the context of the ARFragment and pass the name of your .sfb file
.setSource(fragment.context, Uri.parse("FootBall.sfb"))
.build()
//I accepted the CompletableFuture using Async since I created my model on creation of the activity. You could simply use .thenAccept too.
//Use the returned modelRenderable and save it to a global variable of the same name
.thenAcceptAsync { modelRenderable -> this#MainActivity.modelRenderable = modelRenderable }
The major chunk of the programming has to be done on the frame's onUpdate method. So you attach a listener for frame updates like so
fragment.arSceneView.scene.addOnUpdateListener(this#MainActivity) //You can do this anywhere. I do it on activity creation post inflating the fragment
now you handle adding an object on the listener.
override fun onUpdate(frameTime: FrameTime?) {
//get the frame from the scene for shorthand
val frame = fragment.arSceneView.arFrame
if (frame != null) {
//get the trackables to ensure planes are detected
val var3 = frame.getUpdatedTrackables(Plane::class.java).iterator()
while(var3.hasNext()) {
val plane = var3.next() as Plane
//If a plane has been detected & is being tracked by ARCore
if (plane.trackingState == TrackingState.TRACKING) {
//Hide the plane discovery helper animation
fragment.planeDiscoveryController.hide()
//Get all added anchors to the frame
val iterableAnchor = frame.updatedAnchors.iterator()
//place the first object only if no previous anchors were added
if(!iterableAnchor.hasNext()) {
//Perform a hit test at the center of the screen to place an object without tapping
val hitTest = frame.hitTest(frame.screenCenter().x, frame.screenCenter().y)
//iterate through all hits
val hitTestIterator = hitTest.iterator()
while(hitTestIterator.hasNext()) {
val hitResult = hitTestIterator.next()
//Create an anchor at the plane hit
val modelAnchor = plane.createAnchor(hitResult.hitPose)
//Attach a node to this anchor with the scene as the parent
val anchorNode = AnchorNode(modelAnchor)
anchorNode.setParent(fragment.arSceneView.scene)
//create a new TranformableNode that will carry our object
val transformableNode = TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable = this#MainActivity.modelRenderable
//Alter the real world position to ensure object renders on the table top. Not somewhere inside.
transformableNode.worldPosition = Vector3(modelAnchor.pose.tx(),
modelAnchor.pose.compose(Pose.makeTranslation(0f, 0.05f, 0f)).ty(),
modelAnchor.pose.tz())
}
}
}
}
}
}
I used one extension method
//A method to find the screen center. This is used while placing objects in the scene
private fun Frame.screenCenter(): Vector3 {
val vw = findViewById<View>(android.R.id.content)
return Vector3(vw.width / 2f, vw.height / 2f, 0f)
}
This is the end result

If you don't want to use hit-testing or button's action methods for placing an object in a real environment, you can use, for instance, a camera's Pose for auto-placement (remember, you have to add an ARAnchor, its corresponding Node and a Renderable in front of the ARCamera i.e. along -Z direction):
if (this.anchorNode == null) {
Session session = arFragment.getArSceneView().getSession();
float[] position = { 0, 0, -0.75 }; // 75 cm away from camera
float[] rotation = { 0, 0, 0, 1 };
Anchor anchor = session.createAnchor(new Pose(position, rotation));
anchorNode = new AnchorNode(anchor);
anchorNode.setRenderable(yourModelRenderable);
anchorNode.setParent(arFragment.getArSceneView().getScene());
}
Hope this helps.

Here is the code snippet if you want to place only one object.. Thanks #clinkz
override fun onUpdate(frameTime: FrameTime?) {
arFragment?.let { fragment ->
fragment.arSceneView?.let { sceneView ->
sceneView.arFrame?.let { frame ->
if (!placed) {
val trackable = frame.getUpdatedTrackables(Plane::class.java).iterator()
if (trackable.hasNext()) {
val plane = trackable.next() as Plane
if (plane.trackingState == TrackingState.TRACKING) {
fragment.planeDiscoveryController?.hide()
val hitTest =
frame.hitTest(frame.screenCenter().x, frame.screenCenter().y)
val hitTestIterator = hitTest.iterator()
if (hitTestIterator.hasNext()) {
val hitResult = hitTestIterator.next()
val modelAnchor = plane.createAnchor(hitResult.hitPose)
val anchorNode = AnchorNode(modelAnchor)
anchorNode.setParent(sceneView.scene)
val transformableNode =
TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable = this#ARActivity.modelRenderable
transformableNode.worldPosition = Vector3(
modelAnchor.pose.tx(),
modelAnchor.pose.compose(
Pose.makeTranslation(
0f,
0.05f,
0f
)
).ty(),
modelAnchor.pose.tz()
)
placed = true
}
}
}
}
}
}
}
}
private fun Frame.screenCenter(): Vector3 {
val vw = findViewById<View>(android.R.id.content)
return Vector3(vw.width / 2f, vw.height / 2f, 0f)
}

Related

How to add text outlines to text within Powerpoint via Apache POI:

Does anyone have an idea how we can add outlines to text (text outline) within powerpoint templates (ppxt) using Apache POI? What I have gathered so far is that the XSLFTextRun class does not have a method to get/ set the text outline for a given run element.
And as such, I could only persist the following font/ text styles:
def fontStyles(textBox: XSLFTextBox, textRun: XSLFTextRun): Unit = {
val fontFamily = textRun.getFontFamily
val fontColor = textRun.getFontColor
val fontSize = textRun.getFontSize
val fontBold = textRun.isBold
val fontItalic = textRun.isItalic
val textAlign = textRun.getParagraph.getTextAlign
textBox.getTextParagraphs.foreach { p =>
p.getTextRuns.foreach { tr =>
tr.setFontFamily(fontFamily)
tr.setFontColor(fontColor)
tr.setFontSize(fontSize)
tr.setBold(fontBold)
tr.setItalic(fontItalic)
tr.getParagraph.setTextAlign(textAlign)
}
}
}
Is it possible to add text outline?
Any assistance/ suggestions would be highly appreciated.
Apache poi uses underlying ooxml-schemas classes. Those are auto generated from Office Open XML standard. So they are more complete than the high level XSLF classes. Of course they are much less convenient.
So if somewhat is not implemented in high level XSLF classes, we can get the underlying CT classes and do it using those. In case of XSLFTextRun we can get the CTRegularTextRun object. Then we can look whether there are run properties already. If not, we add one. Then we look whether there is outline set already. If so, we unset it, because we want set it new. Then we set a new outline. This simply is a line having a special color. That line is represented by CTLineProperties object. So we need to have methods to create that CTLineProperties, to set CTLineProperties to the XSLFTextRun and get CTLineProperties from XSLFTextRun.
Complete example using Java code:
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;
import java.awt.Rectangle;
public class PPTXTextRunOutline {
static org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties createSolidFillLineProperties(java.awt.Color color) {
// create new CTLineProperties
org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties lineProperties
= org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties.Factory.newInstance();
// set line solid fill color
lineProperties.addNewSolidFill().addNewSrgbClr().setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});
return lineProperties;
}
static void setOutline(XSLFTextRun run, org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties lineProperties) {
// get underlying CTRegularTextRun object
org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun ctRegularTextRun
= (org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun)run.getXmlObject();
// Are there run properties already? If not, add one.
if (ctRegularTextRun.getRPr() == null) ctRegularTextRun.addNewRPr();
// Is there outline set already? If so, unset it, because we are creating it new.
if (ctRegularTextRun.getRPr().isSetLn()) ctRegularTextRun.getRPr().unsetLn();
// set a new outline
ctRegularTextRun.getRPr().setLn(lineProperties);
}
static org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties getOutline(XSLFTextRun run) {
// get underlying CTRegularTextRun object
org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun ctRegularTextRun
= (org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun)run.getXmlObject();
// Are there run properties already? If not, return null.
if (ctRegularTextRun.getRPr() == null) return null;
// get outline, may be null
org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties lineProperties = ctRegularTextRun.getRPr().getLn();
// make a copy to avoid orphaned exceptions or value disconnected exception when set to its own XML parent
if (lineProperties != null) lineProperties = (org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties)lineProperties.copy();
return lineProperties;
}
// your method fontStyles taken to Java code
static void fontStyles(XSLFTextRun templateRun, XSLFTextShape textShape) {
String fontFamily = templateRun.getFontFamily();
PaintStyle fontColor = templateRun.getFontColor();
Double fontSize = templateRun.getFontSize();
boolean fontBold = templateRun.isBold();
boolean fontItalic = templateRun.isItalic();
TextParagraph.TextAlign textAlign = templateRun.getParagraph().getTextAlign();
org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties lineProperties = getOutline(templateRun);
for (XSLFTextParagraph paragraph : textShape.getTextParagraphs()) {
for (XSLFTextRun run : paragraph.getTextRuns()) {
run.setFontFamily(fontFamily);
if(run != templateRun) run.setFontColor(fontColor); // set PaintStyle has the issue which I am avoiding by using a copy of the underlying XML
run.setFontSize(fontSize);
run.setBold(fontBold);
run.setItalic(fontItalic);
run.getParagraph().setTextAlign(textAlign);
setOutline(run, lineProperties);
}
}
}
public static void main(String[] args) throws Exception {
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("./PPTXIn.pptx"));
XSLFSlide slide = slideShow.getSlides().get(0);
//as in your code, get a template text run and set its font style to all other runs in text shape
if (slide.getShapes().size() > 0) {
XSLFShape shape = slide.getShapes().get(0);
if (shape instanceof XSLFTextShape) {
XSLFTextShape textShape = (XSLFTextShape) shape;
XSLFTextParagraph paragraph = null;
if(textShape.getTextParagraphs().size() > 0) paragraph = textShape.getTextParagraphs().get(0);
if (paragraph != null) {
XSLFTextRun run = null;
if(paragraph.getTextRuns().size() > 0) run = paragraph.getTextRuns().get(0);
if (run != null) {
fontStyles(run, textShape);
}
}
}
}
//new text box having outlined text from scratch
XSLFTextBox textbox = slide.createTextBox();
textbox.setAnchor(new Rectangle(100, 300, 570, 80));
XSLFTextParagraph paragraph = null;
if(textbox.getTextParagraphs().size() > 0) paragraph = textbox.getTextParagraphs().get(0);
if(paragraph == null) paragraph = textbox.addNewTextParagraph();
XSLFTextRun run = paragraph.addNewTextRun();
run.setText("Test text outline");
run.setFontSize(60d);
run.setFontColor(java.awt.Color.YELLOW);
setOutline(run, createSolidFillLineProperties(java.awt.Color.BLUE));
FileOutputStream out = new FileOutputStream("./PPTXOit.pptx");
slideShow.write(out);
out.close();
}
}
Tested and works using current apache poi 5.0.0.

JavaFx Charts highlight entire curve on hover

I am using a logarithmic scale for a graph and I want to be able to make the individual curves a little wider when hovered over and on top of all the other curves as well as the color key's value too. Below is a picture better illustrating what I want to do (with sensitive data redacted)
Is something like this even possible? And if so what direction should I move in to achieve this?
The first of your cases, which is applying the visual changes when the mouse hovers over the curve, is possible by modifying the Node that represents the Series on the chart, which is a Path. You can apply the changes to the stroke of the Path making it darker, wider and bringing in to the front when the mouse enters and reverting them when the mouse leaves
The second, which is applying the visual changes when hovering over the legend items is still possible but it's not as clean a solution, at least it's not in my implementation below. With a Node lookup you can get the items and cast them to either a Label or a LegendItem which expose the graphic and text. I chose Label to avoid using the internal API
See more here: It is a bad practice to use Sun's proprietary Java classes?
With String comparisons between the legend text and series names you can associate the two assuming each series has a name and that it is unique. If it isn't unique you could compare the stroke fills as well as the names
Important: These assumptions limit this approach and so if possible I'd avoid it
SSCCE:
public class DarkerSeriesOnHoverExample extends Application {
#SuppressWarnings("unchecked")
#Override
public void start(Stage primaryStage) throws Exception {
//LogarithmicNumberAxis source: https://stackoverflow.com/a/22424519/5556314
LineChart lineChart = new LineChart(new LogarithmicNumberAxis(1, 1000000), new NumberAxis(0, 2.25, 0.25));
lineChart.setCreateSymbols(false);
//Values guessed from the screen shot
ObservableList<XYChart.Data> seriesData = FXCollections.observableArrayList(new XYChart.Data(1, 2),
new XYChart.Data(10, 2), new XYChart.Data(100, 2), new XYChart.Data(1000, 1.85),
new XYChart.Data(10000, 1.50), new XYChart.Data(100000, 1.20), new XYChart.Data(1000000, 0.9));
ObservableList<XYChart.Data> series2Data = FXCollections.observableArrayList(new XYChart.Data(1, 2),
new XYChart.Data(10, 2), new XYChart.Data(100, 2), new XYChart.Data(1000, 1.60),
new XYChart.Data(10000, 1.25), new XYChart.Data(100000, 0.95), new XYChart.Data(1000000, 0.65));
ObservableList<XYChart.Data> series3Data = FXCollections.observableArrayList(new XYChart.Data(1, 2),
new XYChart.Data(10, 1.85), new XYChart.Data(100, 1.55), new XYChart.Data(1000, 1),
new XYChart.Data(10000, 0.65), new XYChart.Data(100000, 0.5), new XYChart.Data(1000000, 0.45));
ObservableList<XYChart.Series> displayedSeries = FXCollections.observableArrayList(
new XYChart.Series("Series 1", seriesData), new XYChart.Series("Series 2", series2Data),
new XYChart.Series("Series 3", series3Data));
lineChart.getData().addAll(displayedSeries);
Scene scene = new Scene(lineChart, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
darkenSeriesOnHover(displayedSeries); //Setup for hovering on series (cleaner)
darkenSeriesOnLegendHover(lineChart); //Setup both hovering on series and legend (messier)
}
private void darkenSeriesOnHover(List<XYChart.Series> seriesList){
for(XYChart.Series series : seriesList){
Node seriesNode = series.getNode();
//seriesNode will be null if this method is called before the scene CSS has been applied
if(seriesNode != null && seriesNode instanceof Path){
Path seriesPath = (Path) seriesNode;
Color initialStrokeColor = (Color)seriesPath.getStroke();
double initialStrokeWidth = seriesPath.getStrokeWidth();
seriesPath.setOnMouseEntered(event -> {
updatePath(seriesPath, initialStrokeColor.darker(), initialStrokeWidth*2, true);
});
seriesPath.setOnMouseExited(event -> {
//Reset
updatePath(seriesPath, initialStrokeColor, initialStrokeWidth, false);
});
}
}
}
private void darkenSeriesOnLegendHover(LineChart lineChart){
Set<Node> legendItems = lineChart.lookupAll("Label.chart-legend-item");
List<XYChart.Series> seriesList = lineChart.getData();
//Will be empty if this method is called before the scene CSS has been applied
if(legendItems.isEmpty()){ return; }
for(Node legendItem : legendItems){
Label legend = (Label) legendItem;
XYChart.Series matchingSeries = getMatchingSeriesByName(seriesList, legend.getText());
if(matchingSeries == null){ return; }
Node seriesNode = matchingSeries.getNode();
//seriesNode will be null if this method is called before the scene CSS has been applied
if(seriesNode != null && seriesNode instanceof Path){
Path seriesPath = (Path) seriesNode;
Color initialStrokeColor = (Color)seriesPath.getStroke();
double initialStrokeWidth = seriesPath.getStrokeWidth();
legendItem.setOnMouseEntered(event -> {
updatePath(seriesPath, initialStrokeColor.darker(), initialStrokeWidth*2, true);
});
legendItem.setOnMouseExited(event -> {
//Reset
updatePath(seriesPath, initialStrokeColor, initialStrokeWidth, false);
});
seriesPath.setOnMouseEntered(event -> {
updatePath(seriesPath, initialStrokeColor.darker(), initialStrokeWidth*2, true);
});
seriesPath.setOnMouseExited(event -> {
//Reset
updatePath(seriesPath, initialStrokeColor, initialStrokeWidth, false);
});
}
}
}
private void updatePath(Path seriesPath, Paint strokeColor, double strokeWidth, boolean toFront){
seriesPath.setStroke(strokeColor);
seriesPath.setStrokeWidth(strokeWidth);
if(!toFront){ return; }
seriesPath.toFront();
}
private XYChart.Series getMatchingSeriesByName(List<XYChart.Series> seriesList, String searchParam){
for (XYChart.Series series : seriesList){
if(series.getName().equals(searchParam)){
return series;
}
}
return null;
}
}
Output:
Before vs Hover

SWT drop cursor position on canvas

I'm making a simple "paint" application in JAVA. I would have wanted that when the person clicks the canvas, and make a drag and drop, a listener get the drop cursor location, but I don't find how make a drop listener. How can I find the location of the cursor when the user stop his click?
I have the following code for the drag :
Canvas paintC = new Canvas(shell, SWT.NONE);
paintC.addDragDetectListener(new DragDetectListener() {
public void dragDetected(DragDetectEvent arg0) {
Point controlRelativePos = new Point(arg0.x, arg0.y);
displayRelativePos1 = paintC.toDisplay(controlRelativePos);
GC gc = new GC(paintC);
gc.setBackground(SWTResourceManager.getColor(SWT.COLOR_YELLOW));
gc.fillRectangle(arg0.x, arg0.y, 90, 60);
}
});
Should I a drag function in order to get the latest position?
Edit: I've tried this, but it didn't work :
dropTarget.addDropListener(new DropTargetAdapter() {
#Override
public void drop(DropTargetEvent event) {
displayRelativePos2 = dropTarget.getDisplay().getCursorLocation();
hauteur = displayRelativePos2.y - displayRelativePos1.y;
largeur = displayRelativePos2.x - displayRelativePos1.x;
GC gc = new GC(paintC);
gc.setBackground(SWTResourceManager.getColor(SWT.COLOR_RED));
gc.fillRectangle(displayRelativePos1.x, displayRelativePos1.y, largeur, hauteur);
nbFormesAff = nbFormes +1;
forme = "Rectangle" + nbFormesAff;
pos = displayRelativePos1.x + ", " + displayRelativePos1.y +"\nhauteur:" + hauteur +" largeur:"+ largeur;
}
DropTargetEvent has x and y fields which contain the Display relative location of the cursor.
Point displayRelativeDrop = new Point(event.x, event.y);
Your fillRectangle must use points which are relative to the Control (paintC) not the display. Use Control.toControl(point) to convert from display relative to control relative.
You should also not try to draw the control in the drop method. Just call redraw on the control and do the drawing in a paint listener.

Direct Force Layout customization - d3.js

First question on Stack Overflow, so bear with me! I am new to d3.js, but have been consistently amazed by what others are able to accomplish with it... and almost as amazed by how little headway I've been able to make with it myself! Clearly I'm not grokking something, so I hope that the kind souls here can show me the light.
My intention is to make a connected graph based on the CSV data. My CSV data has different information some of them need to be represented as a nodes, some of them need to be used as an information for ltool-tip. I can read the data from CSV by using this snippet of code:
d3.csv("data/project.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem);
});
Which will connect the node P1, to three nodes Problems (URLs).
The problem comes after, I could not see the label on the selected nodes, How could I use the extract information in the CSV files such as "Date, Summary, URL". Is there any way to use mouse click, when I click the node I need its information appears on SVG board to be used for further analysis, such as showing the URL, short text of the summary, and when the user click on the board it should show the the complete information.
Here is the code that I used from this link
var width = 800,
height = 600;
var svg = d3.select("#visualization")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("svg:g");
var force = d3.layout.force()
.gravity(0.2)
.distance(200)
.charge(-1500)
.size([width, height]);
var container = svg.append("g")
.attr("id", "container");
d3.csv("data/project.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem);
});
// Extract the array of nodes from the map by name.
var nodes = d3.values(nodesByName);
//define a scale for color mapping
var colormapping = d3.scale.ordinal()
.domain([0,nodes.length])
.range(['#A700E6','#D95B96','#F4DA88','#22C1BE','#F24957','#DBEF91','#CF8EE8','#FF9B58','#B8FFC4','#91AEFF','#E873D3','#CCB298']);
//create label node tooltip
var labeltooltip = d3.select("body").append("div")
.attr("class", "labeltooltip")
.style("opacity", 1e-6);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", function() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
});
svg.call(zoom);
//links
var link = container.selectAll(".line")
.data(links)
.enter()
.append("line")
.attr("stroke-width",4)
// .attr("stroke-width",function (d) { return linethickness(d.value); })
.style("stroke", "gray");
// Create the node circles.
var node = container.selectAll(".node")
.data(nodes)
.enter()
.append("circle")
.attr("class", "node")
.attr("r", 20)
.attr("fill", function (d,i) {return d3.rgb(colormapping(i)); })
.call(force.drag);
// Start the force layout.
force
.nodes(nodes)
.links(links)
.on("tick", tick)
.start();
node.on("mousemove", function(d) {
labeltooltip.selectAll("p").remove();
labeltooltip.style("left", (d3.event.pageX+15) + "px").style("top", (d3.event.pageY-10) + "px");
labeltooltip.append("p").attr("class", "tooltiptext").html("<span>Id: </span>" + d.Score );
labeltooltip.append("p").attr("class", "tooltiptext").html("<span>Score: </span>" + d.Score);
});
node.on("mouseover", function(d) {
labeltooltip.transition()
.duration(500)
.style("opacity", 1);
link.style('stroke', function(l) {
if (d === l.source || d === l.target)
return d3.rgb('#C20606');
else
return 'gray';
});
link.style('opacity', function(o) {
return o.source === d || o.target === d ? 1 : 0;
});
node.style("opacity", function(o) {
if (o.id != d.id)
return neighboring(d.id, o.id) ? 1 : 0;
});
});
node.on("mouseout", function(d) {
labeltooltip.transition()
.duration(500)
.style("opacity", 1e-6);
link.style('stroke', 'gray');
link.style('opacity', 1);
node.style("opacity", 1);
});
var circletext = node.append("svg:text")
.text(function(d) {return d.name;})
.attr("class","labelText");
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
circletext.attr("x", function(d) { return d.x-25; });
circletext.attr("y", function(d) { return d.y-25;});
}
function nodeByName(name) {
return nodesByName[name] || (nodesByName[name] = {name: name});
}
addZoomMoveIcon("#labelgraph");
});
UPDATE
My CSV data
Project,Problem, Score,Data,Summary,id
p1,Problem1,10,2014-09-04T13:55:05.623-04:00, text text text text, 1
p1,Problem2,5,2014-09-04T13:55:05.623-04:00, text text text text,2
p1,Problem3,11,2014-09-04T13:55:05.623-04:00, text text text text,3
The final results that I am aiming for would be like the following figure:
Where the yellow box should appear on the SVG when the "problem" node clicked.
The first issue you need to address is where to correctly add the node text. Right now you are nesting the text inside the circles, but the text labels need to be siblings of the circles (they do not even need to live right next to each circle). You can replace this:
var circletext = node.append("svg:text")
.text(function(d) {return d.name;})
.attr("class","labelText");
With:
var circletext = container.selectAll("g")
.data(nodes)
.enter()
.append("text").text(function(d) {return d.name})
.attr("class", "labelText");
(Reference: https://www.dashingd3js.com/svg-text-element)
Next though, if you want to display the Score/Data/Summary note that these are attached to the links, not the nodes (there are only three of them, not four). However, at the point of node creation, you can pass this info from the link to the node. Modify the nodeByName function to add the new attributes for the nodes:
function nodeByName(name,score,data,summary) {
return nodesByName[name] || (nodesByName[name] = {name: name, score: score, data: data, summary: summary});
}
Then modify the call to this function when the links are being created:
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem,link.Score,link.Data,link.Summary);
});
To get the labeltooltip to display in a stationary spot, and not next to the nodes, you'll need to remove the bits on the node mouseover and mouseout events that move the div around, and probably just add the div to the html instead of dynamically adding it.

Xcode image link ImageView into next View Controller

I have made a Xcode project for a tabbed application that displays images of color swatches in a Scrollview. How do I link One of the images in my scrollview to go to the next View Controller? Below is my code and pictures. So when you click on one of the images or swatch color in the scrollview it links to the New Controller.
I have multiple images that scroll down the page of the iPhone, Do I have to loop the images cause there are 24 images. I was able to make one button and link it to the next scene with the interface builder, But I can fit 5 images on the screen..
DecorsViewController_iPhone.h
#import <UIKit/UIKit.h>
#interface DecorsViewController_iPhone : UIViewController
{
IBOutlet UIScrollView *scrollViewDecors;
}
#property (nonatomic, retain) UIView *scrollViewDecors;
#end
DecorsViewController_iPhone.m
#import "DecorsViewController_iPhone.h"
#interface DecorsViewController_iPhone ()
#end
#implementation DecorsViewController_iPhone
#synthesize scrollViewDecors;
const CGFloat kScrollObjHeight = 81.5;
const CGFloat kScrollObjWidth = 320.0;
const NSUInteger kNumImages = 24;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollViewDecors subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
CGFloat curYLoc = 0;
CGFloat curYSpace = 1;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, curYLoc);
view.frame = frame;
curYLoc += (curYSpace + kScrollObjHeight);
}
}
// set the content size so it can be scrollable
[scrollViewDecors setContentSize:CGSizeMake(([scrollViewDecors bounds].size.width), (kNumImages * kScrollObjHeight))]; // Vertical Option
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollViewDecors setBackgroundColor:[UIColor blackColor]];
[scrollViewDecors setCanCancelContentTouches:NO];
scrollViewDecors.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollViewDecors.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollViewDecors.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
// scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"Artwork_iPhone_Decors_Scrollview_%d.png", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollViewDecors addSubview:imageView];
//[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
//- (void)dealloc
//{
// [scrollViewDecors release];
//
// [super dealloc];
//}
//- (void)viewDidLoad
//{
// [super viewDidLoad];
// // Do any additional setup after loading the view, typically from a nib.
//}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
Firstly, you need to add a gesture recogniser to your view with something like:
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(flipView:)];
[singleTapGestureRecognizer setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:singleTapGestureRecognizer];
You then need to implement the 'flipView' method:
- (void)flipView:(UIPanGestureRecognizer *)recognizer {
[self performSegueWithIdentifier:#"textView" sender:self];
}
As you can see in my case, when the method is triggered I perform a segue (see below):
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"textView"])
{
//---Pass text to view
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.bounds.size;
int number;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
number = visibleRect.origin.x / 768;
}
else {
number = visibleRect.origin.x / 320;
}
TextViewController *textViewController = segue.destinationViewController;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
textViewController.text = [appDelegate.textArray objectAtIndex:number];
}
}
The 'number' variable is used to decide which image has been clicked, I divide the visible rects origin by the width of the screen in pixels to calculate which image has been pressed and therefore what data to send to my new view.
In your case, you would use the Y coordinate to perform a calculation to decide which colour has been pressed, possibly something like:
int number;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
number = visibleRect.origin.y / <height of each image on iPad in pixels>;
}
else {
number = visibleRect.origin.y / <height of each image on iPhone in pixels>;
}
Alternatively, you could use a UITableView and just populate the cells with the appropriate colour and then display the new view based on which cell was pressed.
EDIT
Use a UITableView, and populate each cell with your image using custom tableview cells. This is a much easier approach than what you are suggesting.
See these links:
adding images to UItableView
If using iOS 5 -
http://kurrytran.blogspot.co.uk/2011/10/ios-5-storyboard-uitableview-tutorial.html
if not -
http://www.iosdevnotes.com/2011/10/uitableview-tutorial/
You are overcomplicating this task massively, follow the above tutorials and you'll be done in no time. If this answer helped you, please mark it as correct.
You can customize your UIImageView. For example, MyImageView. Set its delegate to your main ScrollView and add UITapGestureRecognizer and TapDetecting Delegate methods.
You can implement in the MyImageView:
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
// single tap
if ([_delegate respondsToSelector:#selector(myImageViewWasSingleTapped:)])
[_delegate myImageViewWasSingleTapped:self];
}
then in your main ScrollView(delegate of MyImageView):
- (void)myImageViewWasSingleTapped:(MyImageView *)miv {
AnotherViewController *asv = [[AnotherViewController alloc] initWithImage: miv];
[self.navigationController pushViewController: asv animated:YES];
[asv release];
}
You can use a button instead of a UIImageView, and set the button's image to your image. Your loop in viewDidLoad would be like this:
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"Artwork_iPhone_Decors_Scrollview_%d.png", i];
UIImage *image = [UIImage imageNamed:imageName];
UIButton *imageButton = [[UIButton alloc] init];
[imageButton setImage:image forState:UIControlStateNormal];
[imageButton addTarget:self action:#selector(pushNextViewController:) forControlEvents:UIControlEventTouchUpInside];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = CGRectMake(0, 0, kScrollObjWidth, kScrollObjHeight);
imageButton.frame = rect;
imageButton.tag = i; // tag our images for later use when we place them in serial fashion
[scrollViewDecors addSubview:imageButton];
// Release imageButton unless you're using ARC
}
And then you'd need to define an action for imageButton, in this case I called it pushNextViewController:
- (void)pushNextViewController:(id)sender
{
UIViewController *yourNextViewController = // initialise your next view controller here
[self.navigationController pushViewController:yourNextViewController animated:YES];
}

Categories